What are the most frequent minor variants in the high-confidence samples?

source("./scripts/startup.R")
The following packages are a base install and will not be unloaded:



The following packages were not previously loaded:



Loading required package: pacman
patient_var_30 = read_feather("processing/patient_var_30.arrow")
maf_histogram = patient_var_30 %>% ggplot(aes(minorfreq)) + geom_histogram(binwidth = 0.01) + theme_pubr()
quantile(patient_var_30$minorfreq, probs = c(.25,.5,.75), na.rm = T)
       25%        50%        75% 
0.01252470 0.01717647 0.02788318 
ggsave("ggsave/maf_histogram.pdf", maf_histogram, width = 3, height = 3)

patient_var_30_for_rank = patient_var_30 %>% drop_na(gene) %>% filter(gene !="") %>%
  mutate(label = paste0(ref_sym, aapos), 
         refnt = str_sub(ref_codon, start = codon_pos, end = codon_pos))
bp = c("A", "T", "C", "G")
lineage_defining_mutations = fread("20220103-TRACE-LineageDefinitions-v9.1.txt", data.table = F) %>%
  filter(nt_ref %in% bp & 
           nt_alt %in% bp & 
           variation_type == "SNP") %>% select(nt_pos, nt_ref, nt_alt)
ldm_map = patient_var_30_for_rank %>% 
  mutate(ldm  = ifelse(ntpos %in% lineage_defining_mutations$nt_pos, TRUE, FALSE)) %>% 
  select(gene, label, ldm) %>% distinct %>% group_by(gene, label) %>% arrange(-ldm) %>%
  filter(row_number()==1)
  

highly_shared_sites_ranked = patient_var_30_for_rank %>% drop_na(gene) %>% filter(gene !="") %>%
  mutate(label = paste0(ref_sym, aapos), 
         refnt = str_sub(ref_codon, start = codon_pos, end = codon_pos)) %>%
  group_by(mcov_id, gene, label) %>%
  tally() %>% 
  arrange(-n) %>% ungroup %>% group_by(gene, label) %>% 
  summarize(label_count = n()) %>% ungroup() %>% arrange(-label_count) %>% mutate(rank = 1:nrow(.)) %>%
  left_join(ldm_map) %>% unique()

# highly_shared_sites_ranked_50 = highly_shared_sites_ranked %>% filter(rank <= 25)
# 
# ((
#   hss_maf_50<-patient_var_30 %>% filter(paste0(gene, aapos) %in% paste0(highly_shared_sites_ranked_50$gene, parse_number(highly_shared_sites_ranked_50$label))) %>% 
#     ggplot(aes(x = as.factor(ntpos), y = minorfreq)) + 
#     #geom_point(alpha = 0.2, position = position_jitter(width = 0.1)) + theme_bw() + 
#     geom_boxplot(outlier.shape = NA, alpha =0.5) + theme_bw() +
#     theme(axis.text.x = element_text(angle=90)) + #geom_boxplot(outlier.alpha = 0) + 
#     xlab("Nucleotide position") + ylab("Minor allele freq") ))
# 
# ggsave("ggsave/hss_maf_50.pdf", hss_maf_50, width = 5, height = 3)


#%>% 
 # left_join(patient_var_30 %>% select(ntpos, gene, ref_sym, aapos, ref_codon, codon_pos) %>% distinct)

# ((
#   highly_shared_sites<- patient_var_30 %>% group_by(ntpos) %>% tally() %>% arrange(desc(n)) %>% 
#        drop_na(ntpos) %>% slice_max(n, n = 35) %>% pull(ntpos) %>% as.numeric()
# ))


sample_n = length(unique(patient_var_30$mcov_id))
#for (this_gene in gene_limits$gene_id) {
  plot_ranks = highly_shared_sites_ranked %>% filter(rank <= 35) %>% 
    ggplot(aes(rank, label_count, label = label)) + 
  geom_line(data = highly_shared_sites_ranked %>% 
              select(!gene) %>% filter(rank <= 35), aes(rank, label_count), color = "grey") +
  scale_y_continuous(trans = "log2", breaks = 2^seq(0,12,1),
                     sec.axis = sec_axis(~./sample_n, labels = scales::label_percent(),
                                           breaks = 2^seq(0,8,1)/100)) + theme_pubr() +
  geom_point(aes(rank, label_count), color = "grey") +
  geom_text_repel(aes(label = label, color = ldm), ylim = c(6,11), xlim = c(NA, NA), angle = 90,
                  segment.size = 0.6, segment.curvature = -1e-20, segment.linetype = 3,
                  max.overlaps = Inf) + coord_cartesian(clip = "off") +
    scale_color_manual(values = c("salmon", "grey")) +
    facet_wrap(~gene)
  
  plot_ranks
#}
ggsave("ggsave/plot_ranks.pdf", plot_ranks, height = 5.5, width = 7)

# Across genome


lineage_defining_mutations

plot_data_LDM_prop = patient_var_30 %>% group_by(MCoVNumber) %>% drop_na(ntpos) %>% 
  summarize(iSNV_count = n(), iSNV = paste0(ntpos, collapse = ","), 
            iSNV_LDM_count = length(ntpos[ntpos %in% lineage_defining_mutations$nt_pos]),
            iSNV_LDM = paste0(ntpos[ntpos %in% lineage_defining_mutations$nt_pos],
                              collapse = ","), prop = iSNV_LDM_count/iSNV_count)

plot_data_LDM_prop %>% ggplot(aes(as.factor(iSNV_count), prop)) + geom_violin(draw_quantiles=c(0.5))

patient_var_30_reversions = patient_var_30 %>% mutate(reversion = minor == str_sub(ref_codon, 
                            start = codon_pos, end = codon_pos)) %>% drop_na(reversion)

# How many of our alleles were reversions?
patient_var_30_reversions %>% summarize(proportion_reversion = sum(reversion==T)/
                                          nrow(patient_var_30))

# How many of our alleles that are reversions are at LDM sites?
patient_var_30_reversions %>% mutate(ldm = ifelse(ntpos %in% lineage_defining_mutations$nt_pos,1,0)) %>% 
  summarize(proportion_reversion = sum(ldm == 1 & reversion == T)/sum(reversion==T))

# obscure the consensus in the VCF
problem_sites_global = fread("problematic_sites_sarsCov2_v8-20211027.vcf", skip = 88) %>%
  filter(FILTER != "mask") %>%
  filter(!grepl('single_src|nanopore', INFO)) %>% pull(POS)
problem_sites_houston = fread("problematic_sites_sarsCov2_v8-20211027.vcf", skip = 88) %>%
  filter(grepl('Houston', INFO)) %>% pull(POS)
problem_sites = unique(c(problem_sites_global, problem_sites_houston))
problem_sites
 [1]    76    78   320   538   660  1001  1814  1947  2087  5393  5498  6309  6310  6312  6866  7396
[17] 12685 13512 13513 13514 13686 13693 18505 18506 19338 19344 19369 19732 21302 21304 21305 21658
[33] 22393 22410 22488 22515 23144 24673 25798 26709 27792 28881 28882 28883 29378  8658 12698 15103
[49] 16130 16132 22892
# UNCOMMENT BELOW IF NECESSARY TO REGENERATE DATA
# consensus <-fread("consensus_minor_changes_20220713.csv", data.table = F) %>% filter(!ntpos %in% problem_sites) %>% filter(!ntpos %in% c(1:265)) %>% filter(!ntpos>29674)
# 
# 
# 
# consensus 
# 
# #
# consensus_count = consensus %>% 
#   mutate(MCoVNumber = mcov_reformat(name)) %>% 
#   select(MCoVNumber, major, ntpos, refnt) %>% 
#   filter(major != refnt) %>% 
#   unique() %>%
#   group_by(ntpos) %>%
#   summarize(MCoVNumber = unique(MCoVNumber)) 
# 
# runs = fread("sample_date_and_run.csv", data.table = F) %>%
#     mutate(MCoVNumber = mcov_reformat(mcov_id))
# 
# consensus_runs = consensus_count %>% left_join(runs) %>% drop_na() %>%
#   select(ntpos, MCoVNumber_possible_contaminant = MCoVNumber, run_consensus = run_group) #has each of the consensus mutations with the MCOV
# 
# # uncomment below if necessary
# #patient_var_30_contaminated = patient_var_30 %>% left_join(consensus_runs) # intensive
# #write_feather(patient_var_30_contaminated, "processing/patient_var_30_contaminated.arrow")
# 
patient_var_30_contaminated = read_feather("processing/patient_var_30_contaminated.arrow")
contaminated_df = patient_var_30_contaminated %>% mutate(ref_nt = str_sub(ref_codon,
                            start = codon_pos, end = codon_pos)) %>%
  select(MCoVNumber, run_group, ntpos, ref_nt, major, minor, MCoVNumber_possible_contaminant, run_consensus)

contaminated_df_tallied = contaminated_df %>%
  filter(run_group == run_consensus) %>%
  group_by(MCoVNumber) %>%
  summarize(n_var_contam = length(unique(ntpos)), MCoVNumber_possible_contaminant) %>%
  group_by(MCoVNumber, MCoVNumber_possible_contaminant) %>%
  summarize(n_var_contam, single_sample = n(), prop_single_sample = single_sample / n_var_contam)
`summarise()` has grouped output by 'MCoVNumber'. You can override using the `.groups` argument.`summarise()` has grouped output by 'MCoVNumber', 'MCoVNumber_possible_contaminant'. You can override using the `.groups` argument.
contaminated_df_tallied_top = contaminated_df_tallied %>% group_by(MCoVNumber) %>% top_n(n=1) %>%
  filter(row_number()==1)
Selecting by prop_single_sample
#Note prop_single_sample is single_sample / n_var_contam (proportion of number of minor variants that resememble consensus in another sample / number of minor variants that resemble any consensus in the run)
# prop single contam is the same as above but the denom is out of n_var
patient_counts_30 = read_feather("processing/patient_counts_30.arrow")
patient_counts_30_anno = patient_counts_30 %>% left_join(contaminated_df_tallied_top) %>%
  mutate(run_num = as.numeric(str_replace(run_group, "Run_", ""))) %>%
  replace(is.na(.),0)
Joining, by = "MCoVNumber"
# Plot: n_var x prob that it's from a single source
plot_contam = patient_counts_30_anno %>% mutate(prop_contam = n_var_contam/n_var, prop_single_contam = single_sample/n_var) 

plot_contam %>% select(n_var, admitted_hospital, prop_contam, prop_single_contam) %>% 
  pivot_longer(cols= c(prop_contam, prop_single_contam), names_to = "type", values_to = "prop")  %>%
  ggplot(aes(x = admitted_hospital, y = prop, 
             fill = type)) + 
  geom_violin(draw_quantiles = c(0.25,0.5,0.75))


median_contam_contam = quantile(plot_contam %>% filter(n_var > 0) %>% 
                                  pull(prop_contam), probs = c(0.5))
print(median_contam_contam)
50% 
0.5 
plot_contam_contam = plot_contam %>% 
  select(n_var, admitted_hospital, prop_contam, prop_single_contam) %>% 
  ggplot(aes(x = n_var, y = prop_contam, 
             fill = admitted_hospital, color = admitted_hospital)) + 
  geom_point(alpha = 0.02) + geom_smooth() + theme_pubr() +
  geom_hline(yintercept = median_contam_contam, linetype = "dashed")

plot_contam_contam = ggMarginal(plot_contam_contam, groupColour = T, groupFill = T, type = "violin",
           draw_quantiles = c(0.25, 0.5, 0.75))
`geom_smooth()` using method = 'gam' and formula = 'y ~ s(x, bs = "cs")'Warning: Removed 450 rows containing non-finite values (`stat_smooth()`).`geom_smooth()` using method = 'gam' and formula = 'y ~ s(x, bs = "cs")'Warning: Removed 450 rows containing non-finite values (`stat_smooth()`).Warning: Removed 450 rows containing missing values (`geom_point()`).
median_single_contam = quantile(plot_contam %>% filter(n_var > 0) %>% 
                                  pull(prop_single_contam), probs = c(0.5))
print(median_single_contam)
      50% 
0.3333333 
plot_contam_single_contam = plot_contam %>% 
  select(n_var, admitted_hospital, prop_contam, prop_single_contam) %>% 
  ggplot(aes(x = n_var, y = prop_single_contam, 
             fill = admitted_hospital, color = admitted_hospital)) + 
  geom_point(alpha = 0.02) + geom_smooth() + theme_pubr() + 
  geom_hline(yintercept = median_single_contam, linetype = "dashed")

plot_contam_single_contam = ggMarginal(plot_contam_single_contam, 
                                       groupColour = T, groupFill = T, 
                                       type = "violin",
           draw_quantiles = c(0.25, 0.5, 0.75))
`geom_smooth()` using method = 'gam' and formula = 'y ~ s(x, bs = "cs")'Warning: Removed 450 rows containing non-finite values (`stat_smooth()`).`geom_smooth()` using method = 'gam' and formula = 'y ~ s(x, bs = "cs")'Warning: Removed 450 rows containing non-finite values (`stat_smooth()`).Warning: Removed 450 rows containing missing values (`geom_point()`).
plot_contam_arranged = ggarrange(plot_contam_contam, plot_contam_single_contam,
                                 align = "v",
                                 labels = "AUTO")
plot_contam_arranged
ggsave("ggsave/plot_contam_arranged.pdf", plot_contam_arranged, height = 3, width = 6)

#consensus_sites_lowct %>% filter(refnt == major)
patient_counts_30 = read_feather("processing/patient_counts_30.arrow")


# criteria to count the mutation
# consensus = if ntpos matches in the list above, then 
# the minor will also match the nt_ref (i.e. reversion) or the nt_alt


ldm = c(paste0(lineage_defining_mutations$nt_alt,
                                      lineage_defining_mutations$nt_pos,
                                      lineage_defining_mutations$nt_ref),
                               paste0(lineage_defining_mutations$nt_ref,
                                      lineage_defining_mutations$nt_pos,
                                      lineage_defining_mutations$nt_alt))
        
minor_consensus_plotdata = patient_var_30 %>% #left_join(consensus) %>% 
    mutate(ref_nt = str_sub(ref_codon, 
                            start = codon_pos, end = codon_pos),
      ref_mutation = paste0(ref_nt, ntpos, minor),
      mutation = paste0(major, ntpos, minor), consensus = 
             ifelse(ntpos %in% lineage_defining_mutations$nt_pos, 
                    ifelse((mutation %in% ldm) | (ref_mutation %in% ldm),
                           TRUE, FALSE),      
                           FALSE)) %>% #filter(consensus == FALSE) %>%
  group_by(ntpos, consensus) %>% 
  summarize(consensus = consensus, n = n()) %>%
  unique %>% drop_na %>% ungroup %>% arrange(-n) %>%
  mutate(rank = 1:nrow(.))
`summarise()` has grouped output by 'ntpos', 'consensus'. You can override using the `.groups` argument.
minor_prevalence_across_genome_unlog <- minor_consensus_plotdata  %>%
    ggplot(aes(x = ntpos, y = n, fill = consensus, color = consensus)) + 
    # label your data too for the SALMON
    geom_bar(stat = "identity") + 
  scale_color_manual(values = c("salmon","grey")) + scale_fill_manual(values = c("salmon","grey")) +
    
      geom_point( aes(x = ntpos, y= n), shape = "") +
    #scale_color_manual(values = c("salmon","black")) + 
  theme_bw() + 
  geom_hline(yintercept = nrow(patient_counts_30)*0.01, linetype="dotted") + 
  xlab("Nucleotide position") + ylab("No. samples w/minor variant at site") + 
  annotate("rect", xmin=27894, xmax=28295, ymin=0, ymax=Inf, alpha=0.2, fill="#85D4E3") + 
  annotate("rect", xmin=28274, xmax=29533, ymin=0, ymax=Inf, alpha=0.2, fill="#F4B5BD") + 
  annotate("rect", xmin=21563, xmax=25384, ymin=0, ymax=Inf, alpha=0.2, fill="#FAD77B") +  xlim(0,29903)

minor_prevalence_across_genome_unlog


minor_prevalence_across_genome_unlog_labeled = 
  minor_prevalence_across_genome_unlog + 
  geom_text_repel(max.overlaps = Inf, ylim  = c(500,NA), size = 3, angle = 90, 
                  segment.linetype = 3, segment.size = 0.6, 
                  segment.curvature = -1e-20, 
                  arrow = arrow(length = unit(0.015, "npc"), 
                                type = "closed"),
                  data = minor_consensus_plotdata %>%
                    filter(rank < 50),
                    aes(x = ntpos, y = n, label = ntpos, color = consensus, fill = consensus))
Warning: Ignoring unknown aesthetics: fill
minor_prevalence_across_genome_unlog_labeled


genes <- fread("ntpos_gene_update.csv", data.table = F)

gene_limits<- genes %>% group_by(gene_id) %>% summarise(start=min(ntpos), end=max(ntpos)) %>% filter(gene_id!="") %>% mutate(molecule="")

gene_arrows<-ggplot(gene_limits, aes(xmin = start, xmax = end, y=molecule, label = gene_id)) +
  geom_gene_arrow(arrowhead_height = unit(3, "mm"), arrowhead_width = unit(1, "mm")) + geom_gene_label() + geom_segment(aes(x=266,y=1.5,xend=13468,yend=1.5), size=0.2) + xlim(0,29903) +
  annotate("text", label="ORF1a", x=5000, y=1.41, size=3) + geom_segment(aes(x=13468,y=1.4,xend=21555,yend=1.4), size=0.2) + annotate("text", label="ORF1b", x=18000, y=1.31, size=3) +
  theme_genes() + ylab(NULL) + xlab(NULL) 
Warning: Using `size` aesthetic for lines was deprecated in ggplot2 3.4.0.
Please use `linewidth` instead.
((
  genome_fig_unlog<-plot_grid(gene_arrows, minor_prevalence_across_genome_unlog_labeled + theme(legend.position = "bottom"), nrow=2, rel_heights=c(0.25,1), axis="lr", align="hv")
))



ggsave("ggsave/genome_fig_unlog.pdf", plot = genome_fig_unlog, height = 5, width = 12)

Characteristics of highly recurrent minor variants

# What's the range of minor allele frequencies the highly recurrent minor variants are found at?
highly_shared_sites_top_ranked = highly_shared_sites_ranked %>% filter(rank <= 35)
highly_shared_sites = patient_var_30_for_rank %>% filter(paste0(gene,".",label) %in%
                                     paste0(highly_shared_sites_top_ranked$gene, ".", 
                                            highly_shared_sites_top_ranked$label)) %>%
          group_by(label, ntpos) %>% 
  summarize(ntpos, ntpos_count = n()) %>% distinct() %>% 
  arrange(-ntpos_count) %>% 
  filter(ntpos_count > (patient_var_30$MCoVNumber %>% unique %>% length)*0.01) %>% pull(ntpos)
`summarise()` has grouped output by 'label', 'ntpos'. You can override using the `.groups` argument.
((
  hss_maf<-patient_var_30 %>% filter(ntpos %in% highly_shared_sites) %>% 
    ggplot(aes(x = as.factor(ntpos), y = minorfreq)) + 
    geom_point(alpha = 0.2, position = position_jitter(width = 0.1)) + theme_bw() + 
    geom_boxplot(outlier.shape = NA, alpha =0.5) + 
    theme(axis.text.x = element_text(angle=90)) + #geom_boxplot(outlier.alpha = 0) + 
    xlab("Nucleotide position") + ylab("Minor allele freq") + 
    scale_y_continuous(trans="log2", breaks = c(0.01*2^(0:5), 0.5))
  ))

ggsave("ggsave/hss_maf.pdf", width = 4, height = 1, plot = hss_maf)


((
  hss_maf_unlog<-patient_var_30 %>% filter(ntpos %in% highly_shared_sites) %>% 
    ggplot(aes(x = as.factor(ntpos), y = minorfreq)) + 
    geom_point(alpha = 0.2, position = position_jitter(width = 0.1)) + theme_bw() + 
    geom_boxplot(outlier.shape = NA, alpha = 0.5) + 
    theme(axis.text.x = element_text(angle=90)) + #geom_boxplot(outlier.alpha = 0) + 
    xlab("Nucleotide position") + ylab("Minor allele freq") #+ 
    #scale_y_continuous(trans="log2", breaks = c(0.01*2^(0:5), 0.5))
  ))
ggsave("ggsave/hss_maf_unlog.pdf", width = 4, height = 2, plot = hss_maf_unlog)

#How many different changes do you find at each recurrently-mutated position? How many such mutations are a reversion to the reference?
hss_info <- fread('hss_data2.csv', data.table = F)

((
  hss_plot = patient_var_30_for_rank %>% mutate(label_gene = paste0(gene, ": ", label)) %>%
    filter(ntpos %in% highly_shared_sites) %>% 
    group_by(ntpos, major, minor) %>% mutate(n=n(), median_frequency = median(minorfreq)) %>%     mutate(change=paste0(major,">",minor)) %>% 
    mutate(ref_reversion=if_else(minor==refnt,"yes","no")) %>% 
    mutate(median_MAF=if_else(median_frequency<0.02, 
                              "low (median <2% MAF)","high (median >=2% MAF)")) %>%
    select(change, n, ref_reversion, ntpos, label_gene, median_MAF) %>% distinct %>%
    ggplot(aes(x=change, y=n, color=ref_reversion)) + 
    geom_bar(stat="identity", aes(fill=median_MAF)) + 
    scale_color_manual(values=c("white","red")) + 
    scale_fill_manual(values=c("darkmagenta","steelblue")) + 
    facet_wrap(ntpos~label_gene, scales="free") + 
    theme_pubr() + theme(axis.text.x=element_text(angle=90))
))
Adding missing grouping variables: `major`, `minor`

ggsave('ggsave/hss_plot.pdf', plot = hss_plot, width = 11, height = 13)
ldm_vector = lineage_defining_mutations$nt_pos
heatmap_spectra_tmp = patient_var_30_for_rank %>% 
  mutate(label_gene = paste0(gene, ": ", label)) %>%
    filter(ntpos %in% highly_shared_sites) %>% 
    group_by(ntpos, major, minor) %>% mutate(n=n(), median_frequency = median(minorfreq)) %>%
  mutate(change=paste0(major,">",minor), 
         transition = ifelse(change %in% c("C>T","T>C","A>G","G>A"), 1, 0)) %>%
     mutate(ref_reversion=if_else(minor==refnt,1,0)) %>% ungroup() %>%
  select(change, n, ntpos, label_gene) %>% distinct %>% 
  group_by(ntpos) %>% mutate(ntpos_n = sum(n)) %>% ungroup() %>%
  mutate(n_prop = n/ntpos_n) %>% select(-n) %>% 
  mutate(ldm = as.factor(ifelse(ntpos %in% ldm_vector, 1, 0))) %>%
  mutate(label = paste0(label_gene, " - ", ntpos, " (", ntpos_n, ")"))


annotation_row_df = heatmap_spectra_tmp %>% select(label, ldm) %>% 
  distinct %>% as.data.frame() %>%
  column_to_rownames("label")
annotation_row_df
#%>%
heatmap_spectra = heatmap_spectra_tmp %>% select(-ldm) %>% spread(change, n_prop) %>% 
  arrange(-ntpos_n) %>% distinct() %>%  
  select(-c(ntpos, label_gene, ntpos_n)) %>% replace(.,is.na(.),0) %>%
  column_to_rownames("label")

annotation_col_df = heatmap_spectra_tmp %>% select(change) %>% distinct %>% 
  mutate(transversion = 
           as.factor(ifelse(!(change %in% c("C>T","T>C","A>G","G>A")), 
                            1, 0))) %>% 
  column_to_rownames("change")

maf = heatmap_spectra_tmp %>% select(ntpos, label) %>% distinct %>%
  left_join(patient_var_30 %>% select(ntpos, minorfreq)) %>% 
  select(label, minorfreq)
Joining, by = "ntpos"
maf_list = split(maf$minorfreq,maf$label)

row_ha = rowAnnotation(df = data.frame(
  ldm = annotation_row_df[rownames(heatmap_spectra),]), 
  col = list(ldm = c(`1`="grey", `0`="white")),
  MAF = anno_boxplot(maf_list, pch = 20, size = unit(0.5, "mm")))


heatmap_spectra_reorder = heatmap_spectra %>% select(c("A>G","G>A","C>T","T>C",
                                               "A>C", "C>A", "A>T", "T>A",
                                               "C>G", "G>C", "G>T", "T>G"))
col_ha = columnAnnotation(df = data.frame(
  transversion = annotation_col_df[colnames(heatmap_spectra_reorder),]), 
                          col = list(transversion = c(`1`="grey", `0`="white")))

heatmap_spectra_hss = Heatmap(heatmap_spectra_reorder,
                              name = "prop/site",
                              col = colorRampPalette(
                                c("white", "brown4"))(100),
                              show_row_dend = F, 
                              cluster_columns = F, left_annotation = row_ha,
                              rect_gp = gpar(col = "grey90", lwd = 1),
                              top_annotation = col_ha,
                              heatmap_legend_param = 
                                list(direction = "vertical")) 
Warning: The input is a data frame-like object, convert it to a matrix.Warning: Values in row annotation 'MAF' have a different order of names from the matrix
row names. It may lead to wrong conclusion of your data. Please double check.
pdf(qq("ggsave/heatmap_spectra_hss.pdf"), width = 6.5, height = 7)
draw(heatmap_spectra_hss, merge_legend = TRUE, 
     heatmap_legend_side = "right", 
    annotation_legend_side = "right")
dev.off()
null device 
          1 
heatmap_spectra_hss

# 
#           border_color = "grey90", colorRampPalette(c("white", "brown4"))(100),
#          treeheight_row = 0, treeheight_col = 10, annotation_col = annotation_col_df,
#          annotation_row = annotation_row_df, annotation_colors = annotation_colors)
# pacman::p_load(ComplexHeatmap)
         
major_minor_table(consensus_runs)
`summarise()` has grouped output by 'run'. You can override using the `.groups` argument.`summarise()` has grouped output by 'run'. You can override using the `.groups` argument.Joining, by = c("run", "ntpos")
null device 
          1 
major_minor_table(consensus_runs)
null device 
          1 
major_minor_table(consensus_runs, all = T, 
                  outfile = "ggsave/heatmap_run_mutation_all.pdf",
                  threshold_sites = minor_consensus_plotdata$ntpos[1:1000] %>% unique)
null device 
          1 
#all minor variants that are found in at least 2% of high-coverage samples in Lythgoe et al https://www.science.org/doi/suppl/10.1126/science.abg0821/suppl_file/abg0821-lythgoe-sm.pdf
lythgoe_hss<-c(29320, 25628, 25807, 20364, 357, 25627, 25532, 11083, 239, 238, 356, 16740, 20989, 19393, 15009, 21826, 19937, 26289,28253,25507,29862,11052,29864,25529,369,22453,13571,29538,21575,75,20993,19473,15474,635,1226,29747,24933,19210,13303,28936,26334,16887)

tonkin_hss<-c(11075L, 11083L, 11074L, 522L, 26780L, 1547L, 14408L, 28253L, 13914L, 26137L, 635L, 241L, 26785L, 683L, 23403L, 28881L, 13778L, 25521L, 14805L, 9491L, 11071L, 13780L, 21575L, 29242L, 9430L, 203L, 3037L, 686L, 3096L, 16375L, 16466L, 17167L, 23559L, 9438L, 21137L, 29051L, 23555L, 26333L, 9474L, 13571L, 16887L, 26787L, 28603L, 24213L, 11651L, 27925L, 514L, 26781L, 558L, 1912L, 9479L, 11073L, 12578L, 26144L, 26681L, 29241L)
intersect(lythgoe_hss, highly_shared_sites)
intersect(tonkin_hss, highly_shared_sites)
homoplasic_site_list<-c(187L, 1059L, 2094L, 3037L, 3130L, 6990L, 8022L, 10323L, 10741L, 11074L, 11083L, 13408L, 14786L, 15324L, 19684L, 20148L, 21137L, 21575L, 24034L, 24378L, 25563L, 26144L, 26461L, 26681L, 28077L, 28826L, 28854L, 29700L)
intersect(homoplasic_site_list, highly_shared_sites)
tally_in_minors<-patient_var_30 %>% filter(ntpos %in% highly_shared_sites) %>% group_by(ntpos) %>% summarise(n_minor_variants_houston=n()) %>% mutate(freq_minor_variants_houston=n_minor_variants_houston/nrow(patient_counts_30))

tally_in_gisaid<-fread('hss_gisaid_tallies.csv', data.table = F) %>% select(ntpos, n_consensus_variants_gisaid=n) %>% mutate(freq_consensus_variants_gisaid=n_consensus_variants_gisaid/3109421) #USA gisaid sequences as of 6/13/2022
#SUPP FIG 10

tally_in_minors_gisaid = fread("processing/tally_in_minors.txt", data.table = F) %>% 
  left_join(minor_consensus_plotdata) %>% mutate(ldm = as.factor(consensus))

tally_in_minors_gisaid
((
  gisaid_vs_hmh_plot = #tally_in_minors %>% left_join( tally_in_gisaid) %>% 
    
    tally_in_minors_gisaid %>%
    ggplot(aes(x=freq_minor_variants_houston, y=freq_consensus_variants_gisaid, 
               color = ldm)) + geom_point(alpha=0.5) + 
    theme_pubr(legend= "right") + 
  xlab("Fraction of samples with minor variant in Houston data") + 
    ylab("Fraction of samples with \n consensus variant in GISAID Global") + 
    geom_text_repel(aes(label=ntpos), max.overlaps = 10, label.size=0.1) + 
    geom_abline(slope = 1, intercept = 0, linetype="dashed", color = "gray") +
    scale_y_continuous(trans="log10") + scale_x_continuous(trans="log10") + theme(legend.position = "bottom")
))

gisaid_vs_hmh_marginal = ggMarginal(gisaid_vs_hmh_plot,
             groupColour = T,
  groupFill = T)

ggsave("ggsave/gisaid_vs_hmh_plot_marginal.pdf", plot = gisaid_vs_hmh_marginal, width = 6, height = 5)
# MUTATION SPECTRA ANALYSIS

# reproducibility analysis from RMD 01
plot_nonreproducible_spectra_heatmap = readRDS(file = "plot_nonreproducible_spectra_heatmap.rds")
plot_reproducible_spectra_heatmap = readRDS(file = "plot_reproducible_spectra_heatmap.rds")

hmap<-table(patient_var_30$major[patient_var_30$major!=""], patient_var_30$minor[patient_var_30$minor!=""]) %>% data.frame() %>%
  ggplot(aes(x=Var1, y=Var2, fill=Freq/sum(Freq))) + geom_tile(colour = "black") +
  scale_fill_gradient(low = "white",
                      high = "darkblue") +
  theme_minimal() +   labs(fill = "Number",
       x = "Consensus allele",
       y = "Minor allele", title = "Post-sample filter (Ct, n_var)") #Most frequently C>T mutations

# Now beecause some peaks are really prevalent like the twin peaks at 29187/8, 
# it's important to not factor that in too much. So let's just assign those mutations
# to equate to the median number a mutation appears which is 1.

mutation_spectra = patient_var_30 %>% unite(col = "spectra_mutation", 
                                            major, ntpos, minor, remove = FALSE)
mutation_spectra_counts = mutation_spectra %>% count(spectra_mutation)

mutation_spectra_counts %>% ggplot(aes(y=n)) + geom_boxplot() + 
  scale_y_continuous(trans = "log1p")

mutation_spectra_counts$n %>% quantile() # median is 1

mutation_spectra_unique = mutation_spectra %>% 
  select(major, minor, spectra_mutation) %>% unique()

hmap_unique <-table(mutation_spectra_unique$major[mutation_spectra_unique$major!=""], mutation_spectra_unique$minor[mutation_spectra_unique$minor!=""]) %>% data.frame() %>%
  ggplot(aes(x=Var1, y=Var2, fill=Freq/sum(Freq))) + geom_tile(colour = "black") + # grid color
  scale_fill_gradient(limits = c(0,0.4), low = "white",
                      high = "darkblue") +
  theme_minimal() +   labs(fill = "Fraction",
       x = "Consensus allele",
       y = "Minor allele", title="Unique minor variants")

rescale_fill = function(hmap_unique) {
  hmap_unique_rescaled = hmap_unique + 
    scale_fill_gradient(limits = c(0,0.4), low = "white",
                      high = "darkblue") +
    geom_label(fill = "white", alpha = 0.3, aes(x = Var1, y = Var2, label = round(Freq/sum(Freq), digits = 2)))
  return(hmap_unique_rescaled)
}

((
  rep_nucleotides = ggarrange(rescale_fill(plot_nonreproducible_spectra_heatmap), 
                              rescale_fill(plot_reproducible_spectra_heatmap), 
                              rescale_fill(hmap), 
                              rescale_fill(hmap_unique), common.legend = T)
))
rep_nucleotides

ggsave("ggsave/heatmap_spectra_replicate_variants.pdf", rep_nucleotides, height = 6, width = 6)
LS0tCnRpdGxlOiAiUiBOb3RlYm9vayIKb3V0cHV0OiBodG1sX25vdGVib29rCi0tLQoKV2hhdCBhcmUgdGhlIG1vc3QgZnJlcXVlbnQgbWlub3IgdmFyaWFudHMgaW4gdGhlIGhpZ2gtY29uZmlkZW5jZSBzYW1wbGVzPwpgYGB7cn0Kc291cmNlKCIuL3NjcmlwdHMvc3RhcnR1cC5SIikKCnBhdGllbnRfdmFyXzMwID0gcmVhZF9mZWF0aGVyKCJwcm9jZXNzaW5nL3BhdGllbnRfdmFyXzMwLmFycm93IikKbWFmX2hpc3RvZ3JhbSA9IHBhdGllbnRfdmFyXzMwICU+JSBnZ3Bsb3QoYWVzKG1pbm9yZnJlcSkpICsgZ2VvbV9oaXN0b2dyYW0oYmlud2lkdGggPSAwLjAxKSArIHRoZW1lX3B1YnIoKQpxdWFudGlsZShwYXRpZW50X3Zhcl8zMCRtaW5vcmZyZXEsIHByb2JzID0gYyguMjUsLjUsLjc1KSwgbmEucm0gPSBUKQpnZ3NhdmUoImdnc2F2ZS9tYWZfaGlzdG9ncmFtLnBkZiIsIG1hZl9oaXN0b2dyYW0sIHdpZHRoID0gMywgaGVpZ2h0ID0gMykKCnBhdGllbnRfdmFyXzMwX2Zvcl9yYW5rID0gcGF0aWVudF92YXJfMzAgJT4lIGRyb3BfbmEoZ2VuZSkgJT4lIGZpbHRlcihnZW5lICE9IiIpICU+JQogIG11dGF0ZShsYWJlbCA9IHBhc3RlMChyZWZfc3ltLCBhYXBvcyksIAogICAgICAgICByZWZudCA9IHN0cl9zdWIocmVmX2NvZG9uLCBzdGFydCA9IGNvZG9uX3BvcywgZW5kID0gY29kb25fcG9zKSkKYnAgPSBjKCJBIiwgIlQiLCAiQyIsICJHIikKbGluZWFnZV9kZWZpbmluZ19tdXRhdGlvbnMgPSBmcmVhZCgiMjAyMjAxMDMtVFJBQ0UtTGluZWFnZURlZmluaXRpb25zLXY5LjEudHh0IiwgZGF0YS50YWJsZSA9IEYpICU+JQogIGZpbHRlcihudF9yZWYgJWluJSBicCAmIAogICAgICAgICAgIG50X2FsdCAlaW4lIGJwICYgCiAgICAgICAgICAgdmFyaWF0aW9uX3R5cGUgPT0gIlNOUCIpICU+JSBzZWxlY3QobnRfcG9zLCBudF9yZWYsIG50X2FsdCkKbGRtX21hcCA9IHBhdGllbnRfdmFyXzMwX2Zvcl9yYW5rICU+JSAKICBtdXRhdGUobGRtICA9IGlmZWxzZShudHBvcyAlaW4lIGxpbmVhZ2VfZGVmaW5pbmdfbXV0YXRpb25zJG50X3BvcywgVFJVRSwgRkFMU0UpKSAlPiUgCiAgc2VsZWN0KGdlbmUsIGxhYmVsLCBsZG0pICU+JSBkaXN0aW5jdCAlPiUgZ3JvdXBfYnkoZ2VuZSwgbGFiZWwpICU+JSBhcnJhbmdlKC1sZG0pICU+JQogIGZpbHRlcihyb3dfbnVtYmVyKCk9PTEpCiAgCgpoaWdobHlfc2hhcmVkX3NpdGVzX3JhbmtlZCA9IHBhdGllbnRfdmFyXzMwX2Zvcl9yYW5rICU+JSBkcm9wX25hKGdlbmUpICU+JSBmaWx0ZXIoZ2VuZSAhPSIiKSAlPiUKICBtdXRhdGUobGFiZWwgPSBwYXN0ZTAocmVmX3N5bSwgYWFwb3MpLCAKICAgICAgICAgcmVmbnQgPSBzdHJfc3ViKHJlZl9jb2Rvbiwgc3RhcnQgPSBjb2Rvbl9wb3MsIGVuZCA9IGNvZG9uX3BvcykpICU+JQogIGdyb3VwX2J5KG1jb3ZfaWQsIGdlbmUsIGxhYmVsKSAlPiUKICB0YWxseSgpICU+JSAKICBhcnJhbmdlKC1uKSAlPiUgdW5ncm91cCAlPiUgZ3JvdXBfYnkoZ2VuZSwgbGFiZWwpICU+JSAKICBzdW1tYXJpemUobGFiZWxfY291bnQgPSBuKCkpICU+JSB1bmdyb3VwKCkgJT4lIGFycmFuZ2UoLWxhYmVsX2NvdW50KSAlPiUgbXV0YXRlKHJhbmsgPSAxOm5yb3coLikpICU+JQogIGxlZnRfam9pbihsZG1fbWFwKSAlPiUgdW5pcXVlKCkKCiMgaGlnaGx5X3NoYXJlZF9zaXRlc19yYW5rZWRfNTAgPSBoaWdobHlfc2hhcmVkX3NpdGVzX3JhbmtlZCAlPiUgZmlsdGVyKHJhbmsgPD0gMjUpCiMgCiMgKCgKIyAgIGhzc19tYWZfNTA8LXBhdGllbnRfdmFyXzMwICU+JSBmaWx0ZXIocGFzdGUwKGdlbmUsIGFhcG9zKSAlaW4lIHBhc3RlMChoaWdobHlfc2hhcmVkX3NpdGVzX3JhbmtlZF81MCRnZW5lLCBwYXJzZV9udW1iZXIoaGlnaGx5X3NoYXJlZF9zaXRlc19yYW5rZWRfNTAkbGFiZWwpKSkgJT4lIAojICAgICBnZ3Bsb3QoYWVzKHggPSBhcy5mYWN0b3IobnRwb3MpLCB5ID0gbWlub3JmcmVxKSkgKyAKIyAgICAgI2dlb21fcG9pbnQoYWxwaGEgPSAwLjIsIHBvc2l0aW9uID0gcG9zaXRpb25faml0dGVyKHdpZHRoID0gMC4xKSkgKyB0aGVtZV9idygpICsgCiMgICAgIGdlb21fYm94cGxvdChvdXRsaWVyLnNoYXBlID0gTkEsIGFscGhhID0wLjUpICsgdGhlbWVfYncoKSArCiMgICAgIHRoZW1lKGF4aXMudGV4dC54ID0gZWxlbWVudF90ZXh0KGFuZ2xlPTkwKSkgKyAjZ2VvbV9ib3hwbG90KG91dGxpZXIuYWxwaGEgPSAwKSArIAojICAgICB4bGFiKCJOdWNsZW90aWRlIHBvc2l0aW9uIikgKyB5bGFiKCJNaW5vciBhbGxlbGUgZnJlcSIpICkpCiMgCiMgZ2dzYXZlKCJnZ3NhdmUvaHNzX21hZl81MC5wZGYiLCBoc3NfbWFmXzUwLCB3aWR0aCA9IDUsIGhlaWdodCA9IDMpCgoKIyU+JSAKICMgbGVmdF9qb2luKHBhdGllbnRfdmFyXzMwICU+JSBzZWxlY3QobnRwb3MsIGdlbmUsIHJlZl9zeW0sIGFhcG9zLCByZWZfY29kb24sIGNvZG9uX3BvcykgJT4lIGRpc3RpbmN0KQoKIyAoKAojICAgaGlnaGx5X3NoYXJlZF9zaXRlczwtIHBhdGllbnRfdmFyXzMwICU+JSBncm91cF9ieShudHBvcykgJT4lIHRhbGx5KCkgJT4lIGFycmFuZ2UoZGVzYyhuKSkgJT4lIAojICAgICAgICBkcm9wX25hKG50cG9zKSAlPiUgc2xpY2VfbWF4KG4sIG4gPSAzNSkgJT4lIHB1bGwobnRwb3MpICU+JSBhcy5udW1lcmljKCkKIyApKQoKCnNhbXBsZV9uID0gbGVuZ3RoKHVuaXF1ZShwYXRpZW50X3Zhcl8zMCRtY292X2lkKSkKI2ZvciAodGhpc19nZW5lIGluIGdlbmVfbGltaXRzJGdlbmVfaWQpIHsKICBwbG90X3JhbmtzID0gaGlnaGx5X3NoYXJlZF9zaXRlc19yYW5rZWQgJT4lIGZpbHRlcihyYW5rIDw9IDM1KSAlPiUgCiAgICBnZ3Bsb3QoYWVzKHJhbmssIGxhYmVsX2NvdW50LCBsYWJlbCA9IGxhYmVsKSkgKyAKICBnZW9tX2xpbmUoZGF0YSA9IGhpZ2hseV9zaGFyZWRfc2l0ZXNfcmFua2VkICU+JSAKICAgICAgICAgICAgICBzZWxlY3QoIWdlbmUpICU+JSBmaWx0ZXIocmFuayA8PSAzNSksIGFlcyhyYW5rLCBsYWJlbF9jb3VudCksIGNvbG9yID0gImdyZXkiKSArCiAgc2NhbGVfeV9jb250aW51b3VzKHRyYW5zID0gImxvZzIiLCBicmVha3MgPSAyXnNlcSgwLDEyLDEpLAogICAgICAgICAgICAgICAgICAgICBzZWMuYXhpcyA9IHNlY19heGlzKH4uL3NhbXBsZV9uLCBsYWJlbHMgPSBzY2FsZXM6OmxhYmVsX3BlcmNlbnQoKSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGJyZWFrcyA9IDJec2VxKDAsOCwxKS8xMDApKSArIHRoZW1lX3B1YnIoKSArCiAgZ2VvbV9wb2ludChhZXMocmFuaywgbGFiZWxfY291bnQpLCBjb2xvciA9ICJncmV5IikgKwogIGdlb21fdGV4dF9yZXBlbChhZXMobGFiZWwgPSBsYWJlbCwgY29sb3IgPSBsZG0pLCB5bGltID0gYyg2LDExKSwgeGxpbSA9IGMoTkEsIE5BKSwgYW5nbGUgPSA5MCwKICAgICAgICAgICAgICAgICAgc2VnbWVudC5zaXplID0gMC42LCBzZWdtZW50LmN1cnZhdHVyZSA9IC0xZS0yMCwgc2VnbWVudC5saW5ldHlwZSA9IDMsCiAgICAgICAgICAgICAgICAgIG1heC5vdmVybGFwcyA9IEluZikgKyBjb29yZF9jYXJ0ZXNpYW4oY2xpcCA9ICJvZmYiKSArCiAgICBzY2FsZV9jb2xvcl9tYW51YWwodmFsdWVzID0gYygic2FsbW9uIiwgImdyZXkiKSkgKwogICAgZmFjZXRfd3JhcCh+Z2VuZSkKICAKICBwbG90X3JhbmtzCiN9Cmdnc2F2ZSgiZ2dzYXZlL3Bsb3RfcmFua3MucGRmIiwgcGxvdF9yYW5rcywgaGVpZ2h0ID0gNS41LCB3aWR0aCA9IDcpCmBgYAoKCgpgYGB7cn0KIyBBY3Jvc3MgZ2Vub21lCgoKbGluZWFnZV9kZWZpbmluZ19tdXRhdGlvbnMKCnBsb3RfZGF0YV9MRE1fcHJvcCA9IHBhdGllbnRfdmFyXzMwICU+JSBncm91cF9ieShNQ29WTnVtYmVyKSAlPiUgZHJvcF9uYShudHBvcykgJT4lIAogIHN1bW1hcml6ZShpU05WX2NvdW50ID0gbigpLCBpU05WID0gcGFzdGUwKG50cG9zLCBjb2xsYXBzZSA9ICIsIiksIAogICAgICAgICAgICBpU05WX0xETV9jb3VudCA9IGxlbmd0aChudHBvc1tudHBvcyAlaW4lIGxpbmVhZ2VfZGVmaW5pbmdfbXV0YXRpb25zJG50X3Bvc10pLAogICAgICAgICAgICBpU05WX0xETSA9IHBhc3RlMChudHBvc1tudHBvcyAlaW4lIGxpbmVhZ2VfZGVmaW5pbmdfbXV0YXRpb25zJG50X3Bvc10sCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGNvbGxhcHNlID0gIiwiKSwgcHJvcCA9IGlTTlZfTERNX2NvdW50L2lTTlZfY291bnQpCgpwbG90X2RhdGFfTERNX3Byb3AgJT4lIGdncGxvdChhZXMoYXMuZmFjdG9yKGlTTlZfY291bnQpLCBwcm9wKSkgKyBnZW9tX3Zpb2xpbihkcmF3X3F1YW50aWxlcz1jKDAuNSkpCgpgYGAKYGBge3J9CnBhdGllbnRfdmFyXzMwX3JldmVyc2lvbnMgPSBwYXRpZW50X3Zhcl8zMCAlPiUgbXV0YXRlKHJldmVyc2lvbiA9IG1pbm9yID09IHN0cl9zdWIocmVmX2NvZG9uLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgIHN0YXJ0ID0gY29kb25fcG9zLCBlbmQgPSBjb2Rvbl9wb3MpKSAlPiUgZHJvcF9uYShyZXZlcnNpb24pCgojIEhvdyBtYW55IG9mIG91ciBhbGxlbGVzIHdlcmUgcmV2ZXJzaW9ucz8KcGF0aWVudF92YXJfMzBfcmV2ZXJzaW9ucyAlPiUgc3VtbWFyaXplKHByb3BvcnRpb25fcmV2ZXJzaW9uID0gc3VtKHJldmVyc2lvbj09VCkvCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIG5yb3cocGF0aWVudF92YXJfMzApKQoKIyBIb3cgbWFueSBvZiBvdXIgYWxsZWxlcyB0aGF0IGFyZSByZXZlcnNpb25zIGFyZSBhdCBMRE0gc2l0ZXM/CnBhdGllbnRfdmFyXzMwX3JldmVyc2lvbnMgJT4lIG11dGF0ZShsZG0gPSBpZmVsc2UobnRwb3MgJWluJSBsaW5lYWdlX2RlZmluaW5nX211dGF0aW9ucyRudF9wb3MsMSwwKSkgJT4lIAogIHN1bW1hcml6ZShwcm9wb3J0aW9uX3JldmVyc2lvbiA9IHN1bShsZG0gPT0gMSAmIHJldmVyc2lvbiA9PSBUKS9zdW0ocmV2ZXJzaW9uPT1UKSkKCiMgb2JzY3VyZSB0aGUgY29uc2Vuc3VzIGluIHRoZSBWQ0YKcHJvYmxlbV9zaXRlc19nbG9iYWwgPSBmcmVhZCgicHJvYmxlbWF0aWNfc2l0ZXNfc2Fyc0NvdjJfdjgtMjAyMTEwMjcudmNmIiwgc2tpcCA9IDg4KSAlPiUKICBmaWx0ZXIoRklMVEVSICE9ICJtYXNrIikgJT4lCiAgZmlsdGVyKCFncmVwbCgnc2luZ2xlX3NyY3xuYW5vcG9yZScsIElORk8pKSAlPiUgcHVsbChQT1MpCnByb2JsZW1fc2l0ZXNfaG91c3RvbiA9IGZyZWFkKCJwcm9ibGVtYXRpY19zaXRlc19zYXJzQ292Ml92OC0yMDIxMTAyNy52Y2YiLCBza2lwID0gODgpICU+JQogIGZpbHRlcihncmVwbCgnSG91c3RvbicsIElORk8pKSAlPiUgcHVsbChQT1MpCnByb2JsZW1fc2l0ZXMgPSB1bmlxdWUoYyhwcm9ibGVtX3NpdGVzX2dsb2JhbCwgcHJvYmxlbV9zaXRlc19ob3VzdG9uKSkKcHJvYmxlbV9zaXRlcwoKIyBVTkNPTU1FTlQgQkVMT1cgSUYgTkVDRVNTQVJZIFRPIFJFR0VORVJBVEUgREFUQQojIGNvbnNlbnN1cyA8LWZyZWFkKCJjb25zZW5zdXNfbWlub3JfY2hhbmdlc18yMDIyMDcxMy5jc3YiLCBkYXRhLnRhYmxlID0gRikgJT4lIGZpbHRlcighbnRwb3MgJWluJSBwcm9ibGVtX3NpdGVzKSAlPiUgZmlsdGVyKCFudHBvcyAlaW4lIGMoMToyNjUpKSAlPiUgZmlsdGVyKCFudHBvcz4yOTY3NCkKIyAKIyAKIyAKIyBjb25zZW5zdXMgCiMgCiMgIwojIGNvbnNlbnN1c19jb3VudCA9IGNvbnNlbnN1cyAlPiUgCiMgICBtdXRhdGUoTUNvVk51bWJlciA9IG1jb3ZfcmVmb3JtYXQobmFtZSkpICU+JSAKIyAgIHNlbGVjdChNQ29WTnVtYmVyLCBtYWpvciwgbnRwb3MsIHJlZm50KSAlPiUgCiMgICBmaWx0ZXIobWFqb3IgIT0gcmVmbnQpICU+JSAKIyAgIHVuaXF1ZSgpICU+JQojICAgZ3JvdXBfYnkobnRwb3MpICU+JQojICAgc3VtbWFyaXplKE1Db1ZOdW1iZXIgPSB1bmlxdWUoTUNvVk51bWJlcikpIAojIAojIHJ1bnMgPSBmcmVhZCgic2FtcGxlX2RhdGVfYW5kX3J1bi5jc3YiLCBkYXRhLnRhYmxlID0gRikgJT4lCiMgICAgIG11dGF0ZShNQ29WTnVtYmVyID0gbWNvdl9yZWZvcm1hdChtY292X2lkKSkKIyAKIyBjb25zZW5zdXNfcnVucyA9IGNvbnNlbnN1c19jb3VudCAlPiUgbGVmdF9qb2luKHJ1bnMpICU+JSBkcm9wX25hKCkgJT4lCiMgICBzZWxlY3QobnRwb3MsIE1Db1ZOdW1iZXJfcG9zc2libGVfY29udGFtaW5hbnQgPSBNQ29WTnVtYmVyLCBydW5fY29uc2Vuc3VzID0gcnVuX2dyb3VwKSAjaGFzIGVhY2ggb2YgdGhlIGNvbnNlbnN1cyBtdXRhdGlvbnMgd2l0aCB0aGUgTUNPVgojIAojICMgdW5jb21tZW50IGJlbG93IGlmIG5lY2Vzc2FyeQojICNwYXRpZW50X3Zhcl8zMF9jb250YW1pbmF0ZWQgPSBwYXRpZW50X3Zhcl8zMCAlPiUgbGVmdF9qb2luKGNvbnNlbnN1c19ydW5zKSAjIGludGVuc2l2ZQojICN3cml0ZV9mZWF0aGVyKHBhdGllbnRfdmFyXzMwX2NvbnRhbWluYXRlZCwgInByb2Nlc3NpbmcvcGF0aWVudF92YXJfMzBfY29udGFtaW5hdGVkLmFycm93IikKIyAKcGF0aWVudF92YXJfMzBfY29udGFtaW5hdGVkID0gcmVhZF9mZWF0aGVyKCJwcm9jZXNzaW5nL3BhdGllbnRfdmFyXzMwX2NvbnRhbWluYXRlZC5hcnJvdyIpCmNvbnRhbWluYXRlZF9kZiA9IHBhdGllbnRfdmFyXzMwX2NvbnRhbWluYXRlZCAlPiUgbXV0YXRlKHJlZl9udCA9IHN0cl9zdWIocmVmX2NvZG9uLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgc3RhcnQgPSBjb2Rvbl9wb3MsIGVuZCA9IGNvZG9uX3BvcykpICU+JQogIHNlbGVjdChNQ29WTnVtYmVyLCBydW5fZ3JvdXAsIG50cG9zLCByZWZfbnQsIG1ham9yLCBtaW5vciwgTUNvVk51bWJlcl9wb3NzaWJsZV9jb250YW1pbmFudCwgcnVuX2NvbnNlbnN1cykKCmNvbnRhbWluYXRlZF9kZl90YWxsaWVkID0gY29udGFtaW5hdGVkX2RmICU+JQogIGZpbHRlcihydW5fZ3JvdXAgPT0gcnVuX2NvbnNlbnN1cykgJT4lCiAgZ3JvdXBfYnkoTUNvVk51bWJlcikgJT4lCiAgc3VtbWFyaXplKG5fdmFyX2NvbnRhbSA9IGxlbmd0aCh1bmlxdWUobnRwb3MpKSwgTUNvVk51bWJlcl9wb3NzaWJsZV9jb250YW1pbmFudCkgJT4lCiAgZ3JvdXBfYnkoTUNvVk51bWJlciwgTUNvVk51bWJlcl9wb3NzaWJsZV9jb250YW1pbmFudCkgJT4lCiAgc3VtbWFyaXplKG5fdmFyX2NvbnRhbSwgc2luZ2xlX3NhbXBsZSA9IG4oKSwgcHJvcF9zaW5nbGVfc2FtcGxlID0gc2luZ2xlX3NhbXBsZSAvIG5fdmFyX2NvbnRhbSkKCmNvbnRhbWluYXRlZF9kZl90YWxsaWVkX3RvcCA9IGNvbnRhbWluYXRlZF9kZl90YWxsaWVkICU+JSBncm91cF9ieShNQ29WTnVtYmVyKSAlPiUgdG9wX24obj0xKSAlPiUKICBmaWx0ZXIocm93X251bWJlcigpPT0xKQojTm90ZSBwcm9wX3NpbmdsZV9zYW1wbGUgaXMgc2luZ2xlX3NhbXBsZSAvIG5fdmFyX2NvbnRhbSAocHJvcG9ydGlvbiBvZiBudW1iZXIgb2YgbWlub3IgdmFyaWFudHMgdGhhdCByZXNlbWVtYmxlIGNvbnNlbnN1cyBpbiBhbm90aGVyIHNhbXBsZSAvIG51bWJlciBvZiBtaW5vciB2YXJpYW50cyB0aGF0IHJlc2VtYmxlIGFueSBjb25zZW5zdXMgaW4gdGhlIHJ1bikKIyBwcm9wIHNpbmdsZSBjb250YW0gaXMgdGhlIHNhbWUgYXMgYWJvdmUgYnV0IHRoZSBkZW5vbSBpcyBvdXQgb2Ygbl92YXIKcGF0aWVudF9jb3VudHNfMzAgPSByZWFkX2ZlYXRoZXIoInByb2Nlc3NpbmcvcGF0aWVudF9jb3VudHNfMzAuYXJyb3ciKQpwYXRpZW50X2NvdW50c18zMF9hbm5vID0gcGF0aWVudF9jb3VudHNfMzAgJT4lIGxlZnRfam9pbihjb250YW1pbmF0ZWRfZGZfdGFsbGllZF90b3ApICU+JQogIG11dGF0ZShydW5fbnVtID0gYXMubnVtZXJpYyhzdHJfcmVwbGFjZShydW5fZ3JvdXAsICJSdW5fIiwgIiIpKSkgJT4lCiAgcmVwbGFjZShpcy5uYSguKSwwKQoKIyBQbG90OiBuX3ZhciB4IHByb2IgdGhhdCBpdCdzIGZyb20gYSBzaW5nbGUgc291cmNlCnBsb3RfY29udGFtID0gcGF0aWVudF9jb3VudHNfMzBfYW5ubyAlPiUgbXV0YXRlKHByb3BfY29udGFtID0gbl92YXJfY29udGFtL25fdmFyLCBwcm9wX3NpbmdsZV9jb250YW0gPSBzaW5nbGVfc2FtcGxlL25fdmFyKSAKCnBsb3RfY29udGFtICU+JSBzZWxlY3Qobl92YXIsIGFkbWl0dGVkX2hvc3BpdGFsLCBwcm9wX2NvbnRhbSwgcHJvcF9zaW5nbGVfY29udGFtKSAlPiUgCiAgcGl2b3RfbG9uZ2VyKGNvbHM9IGMocHJvcF9jb250YW0sIHByb3Bfc2luZ2xlX2NvbnRhbSksIG5hbWVzX3RvID0gInR5cGUiLCB2YWx1ZXNfdG8gPSAicHJvcCIpICAlPiUKICBnZ3Bsb3QoYWVzKHggPSBhZG1pdHRlZF9ob3NwaXRhbCwgeSA9IHByb3AsIAogICAgICAgICAgICAgZmlsbCA9IHR5cGUpKSArIAogIGdlb21fdmlvbGluKGRyYXdfcXVhbnRpbGVzID0gYygwLjI1LDAuNSwwLjc1KSkKCm1lZGlhbl9jb250YW1fY29udGFtID0gcXVhbnRpbGUocGxvdF9jb250YW0gJT4lIGZpbHRlcihuX3ZhciA+IDApICU+JSAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHB1bGwocHJvcF9jb250YW0pLCBwcm9icyA9IGMoMC41KSkKcHJpbnQobWVkaWFuX2NvbnRhbV9jb250YW0pCnBsb3RfY29udGFtX2NvbnRhbSA9IHBsb3RfY29udGFtICU+JSAKICBzZWxlY3Qobl92YXIsIGFkbWl0dGVkX2hvc3BpdGFsLCBwcm9wX2NvbnRhbSwgcHJvcF9zaW5nbGVfY29udGFtKSAlPiUgCiAgZ2dwbG90KGFlcyh4ID0gbl92YXIsIHkgPSBwcm9wX2NvbnRhbSwgCiAgICAgICAgICAgICBmaWxsID0gYWRtaXR0ZWRfaG9zcGl0YWwsIGNvbG9yID0gYWRtaXR0ZWRfaG9zcGl0YWwpKSArIAogIGdlb21fcG9pbnQoYWxwaGEgPSAwLjAyKSArIGdlb21fc21vb3RoKCkgKyB0aGVtZV9wdWJyKCkgKwogIGdlb21faGxpbmUoeWludGVyY2VwdCA9IG1lZGlhbl9jb250YW1fY29udGFtLCBsaW5ldHlwZSA9ICJkYXNoZWQiKQoKcGxvdF9jb250YW1fY29udGFtID0gZ2dNYXJnaW5hbChwbG90X2NvbnRhbV9jb250YW0sIGdyb3VwQ29sb3VyID0gVCwgZ3JvdXBGaWxsID0gVCwgdHlwZSA9ICJ2aW9saW4iLAogICAgICAgICAgIGRyYXdfcXVhbnRpbGVzID0gYygwLjI1LCAwLjUsIDAuNzUpKQoKbWVkaWFuX3NpbmdsZV9jb250YW0gPSBxdWFudGlsZShwbG90X2NvbnRhbSAlPiUgZmlsdGVyKG5fdmFyID4gMCkgJT4lIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcHVsbChwcm9wX3NpbmdsZV9jb250YW0pLCBwcm9icyA9IGMoMC41KSkKcHJpbnQobWVkaWFuX3NpbmdsZV9jb250YW0pCnBsb3RfY29udGFtX3NpbmdsZV9jb250YW0gPSBwbG90X2NvbnRhbSAlPiUgCiAgc2VsZWN0KG5fdmFyLCBhZG1pdHRlZF9ob3NwaXRhbCwgcHJvcF9jb250YW0sIHByb3Bfc2luZ2xlX2NvbnRhbSkgJT4lIAogIGdncGxvdChhZXMoeCA9IG5fdmFyLCB5ID0gcHJvcF9zaW5nbGVfY29udGFtLCAKICAgICAgICAgICAgIGZpbGwgPSBhZG1pdHRlZF9ob3NwaXRhbCwgY29sb3IgPSBhZG1pdHRlZF9ob3NwaXRhbCkpICsgCiAgZ2VvbV9wb2ludChhbHBoYSA9IDAuMDIpICsgZ2VvbV9zbW9vdGgoKSArIHRoZW1lX3B1YnIoKSArIAogIGdlb21faGxpbmUoeWludGVyY2VwdCA9IG1lZGlhbl9zaW5nbGVfY29udGFtLCBsaW5ldHlwZSA9ICJkYXNoZWQiKQoKcGxvdF9jb250YW1fc2luZ2xlX2NvbnRhbSA9IGdnTWFyZ2luYWwocGxvdF9jb250YW1fc2luZ2xlX2NvbnRhbSwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGdyb3VwQ29sb3VyID0gVCwgZ3JvdXBGaWxsID0gVCwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHR5cGUgPSAidmlvbGluIiwKICAgICAgICAgICBkcmF3X3F1YW50aWxlcyA9IGMoMC4yNSwgMC41LCAwLjc1KSkKCnBsb3RfY29udGFtX2FycmFuZ2VkID0gZ2dhcnJhbmdlKHBsb3RfY29udGFtX2NvbnRhbSwgcGxvdF9jb250YW1fc2luZ2xlX2NvbnRhbSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgYWxpZ24gPSAidiIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGxhYmVscyA9ICJBVVRPIikKcGxvdF9jb250YW1fYXJyYW5nZWQKZ2dzYXZlKCJnZ3NhdmUvcGxvdF9jb250YW1fYXJyYW5nZWQucGRmIiwgcGxvdF9jb250YW1fYXJyYW5nZWQsIGhlaWdodCA9IDMsIHdpZHRoID0gNikKYGBgCgoKYGBge3J9CiNjb25zZW5zdXNfc2l0ZXNfbG93Y3QgJT4lIGZpbHRlcihyZWZudCA9PSBtYWpvcikKcGF0aWVudF9jb3VudHNfMzAgPSByZWFkX2ZlYXRoZXIoInByb2Nlc3NpbmcvcGF0aWVudF9jb3VudHNfMzAuYXJyb3ciKQoKCiMgY3JpdGVyaWEgdG8gY291bnQgdGhlIG11dGF0aW9uCiMgY29uc2Vuc3VzID0gaWYgbnRwb3MgbWF0Y2hlcyBpbiB0aGUgbGlzdCBhYm92ZSwgdGhlbiAKIyB0aGUgbWlub3Igd2lsbCBhbHNvIG1hdGNoIHRoZSBudF9yZWYgKGkuZS4gcmV2ZXJzaW9uKSBvciB0aGUgbnRfYWx0CgoKbGRtID0gYyhwYXN0ZTAobGluZWFnZV9kZWZpbmluZ19tdXRhdGlvbnMkbnRfYWx0LAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGxpbmVhZ2VfZGVmaW5pbmdfbXV0YXRpb25zJG50X3BvcywKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBsaW5lYWdlX2RlZmluaW5nX211dGF0aW9ucyRudF9yZWYpLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcGFzdGUwKGxpbmVhZ2VfZGVmaW5pbmdfbXV0YXRpb25zJG50X3JlZiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBsaW5lYWdlX2RlZmluaW5nX211dGF0aW9ucyRudF9wb3MsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbGluZWFnZV9kZWZpbmluZ19tdXRhdGlvbnMkbnRfYWx0KSkKICAgICAgICAKbWlub3JfY29uc2Vuc3VzX3Bsb3RkYXRhID0gcGF0aWVudF92YXJfMzAgJT4lICNsZWZ0X2pvaW4oY29uc2Vuc3VzKSAlPiUgCiAgICBtdXRhdGUocmVmX250ID0gc3RyX3N1YihyZWZfY29kb24sIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgc3RhcnQgPSBjb2Rvbl9wb3MsIGVuZCA9IGNvZG9uX3BvcyksCiAgICAgIHJlZl9tdXRhdGlvbiA9IHBhc3RlMChyZWZfbnQsIG50cG9zLCBtaW5vciksCiAgICAgIG11dGF0aW9uID0gcGFzdGUwKG1ham9yLCBudHBvcywgbWlub3IpLCBjb25zZW5zdXMgPSAKICAgICAgICAgICAgIGlmZWxzZShudHBvcyAlaW4lIGxpbmVhZ2VfZGVmaW5pbmdfbXV0YXRpb25zJG50X3BvcywgCiAgICAgICAgICAgICAgICAgICAgaWZlbHNlKChtdXRhdGlvbiAlaW4lIGxkbSkgfCAocmVmX211dGF0aW9uICVpbiUgbGRtKSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgVFJVRSwgRkFMU0UpLCAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICBGQUxTRSkpICU+JSAjZmlsdGVyKGNvbnNlbnN1cyA9PSBGQUxTRSkgJT4lCiAgZ3JvdXBfYnkobnRwb3MsIGNvbnNlbnN1cykgJT4lIAogIHN1bW1hcml6ZShjb25zZW5zdXMgPSBjb25zZW5zdXMsIG4gPSBuKCkpICU+JQogIHVuaXF1ZSAlPiUgZHJvcF9uYSAlPiUgdW5ncm91cCAlPiUgYXJyYW5nZSgtbikgJT4lCiAgbXV0YXRlKHJhbmsgPSAxOm5yb3coLikpCgptaW5vcl9wcmV2YWxlbmNlX2Fjcm9zc19nZW5vbWVfdW5sb2cgPC0gbWlub3JfY29uc2Vuc3VzX3Bsb3RkYXRhICAlPiUKICAgIGdncGxvdChhZXMoeCA9IG50cG9zLCB5ID0gbiwgZmlsbCA9IGNvbnNlbnN1cywgY29sb3IgPSBjb25zZW5zdXMpKSArIAogICAgIyBsYWJlbCB5b3VyIGRhdGEgdG9vIGZvciB0aGUgU0FMTU9OCiAgICBnZW9tX2JhcihzdGF0ID0gImlkZW50aXR5IikgKyAKICBzY2FsZV9jb2xvcl9tYW51YWwodmFsdWVzID0gYygic2FsbW9uIiwiZ3JleSIpKSArIHNjYWxlX2ZpbGxfbWFudWFsKHZhbHVlcyA9IGMoInNhbG1vbiIsImdyZXkiKSkgKwogICAgCiAgICAgIGdlb21fcG9pbnQoIGFlcyh4ID0gbnRwb3MsIHk9IG4pLCBzaGFwZSA9ICIiKSArCiAgICAjc2NhbGVfY29sb3JfbWFudWFsKHZhbHVlcyA9IGMoInNhbG1vbiIsImJsYWNrIikpICsgCiAgdGhlbWVfYncoKSArIAogIGdlb21faGxpbmUoeWludGVyY2VwdCA9IG5yb3cocGF0aWVudF9jb3VudHNfMzApKjAuMDEsIGxpbmV0eXBlPSJkb3R0ZWQiKSArIAogIHhsYWIoIk51Y2xlb3RpZGUgcG9zaXRpb24iKSArIHlsYWIoIk5vLiBzYW1wbGVzIHcvbWlub3IgdmFyaWFudCBhdCBzaXRlIikgKyAKICBhbm5vdGF0ZSgicmVjdCIsIHhtaW49Mjc4OTQsIHhtYXg9MjgyOTUsIHltaW49MCwgeW1heD1JbmYsIGFscGhhPTAuMiwgZmlsbD0iIzg1RDRFMyIpICsgCiAgYW5ub3RhdGUoInJlY3QiLCB4bWluPTI4Mjc0LCB4bWF4PTI5NTMzLCB5bWluPTAsIHltYXg9SW5mLCBhbHBoYT0wLjIsIGZpbGw9IiNGNEI1QkQiKSArIAogIGFubm90YXRlKCJyZWN0IiwgeG1pbj0yMTU2MywgeG1heD0yNTM4NCwgeW1pbj0wLCB5bWF4PUluZiwgYWxwaGE9MC4yLCBmaWxsPSIjRkFENzdCIikgKyAgeGxpbSgwLDI5OTAzKQoKbWlub3JfcHJldmFsZW5jZV9hY3Jvc3NfZ2Vub21lX3VubG9nCgptaW5vcl9wcmV2YWxlbmNlX2Fjcm9zc19nZW5vbWVfdW5sb2dfbGFiZWxlZCA9IAogIG1pbm9yX3ByZXZhbGVuY2VfYWNyb3NzX2dlbm9tZV91bmxvZyArIAogIGdlb21fdGV4dF9yZXBlbChtYXgub3ZlcmxhcHMgPSBJbmYsIHlsaW0gID0gYyg1MDAsTkEpLCBzaXplID0gMywgYW5nbGUgPSA5MCwgCiAgICAgICAgICAgICAgICAgIHNlZ21lbnQubGluZXR5cGUgPSAzLCBzZWdtZW50LnNpemUgPSAwLjYsIAogICAgICAgICAgICAgICAgICBzZWdtZW50LmN1cnZhdHVyZSA9IC0xZS0yMCwgCiAgICAgICAgICAgICAgICAgIGFycm93ID0gYXJyb3cobGVuZ3RoID0gdW5pdCgwLjAxNSwgIm5wYyIpLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB0eXBlID0gImNsb3NlZCIpLAogICAgICAgICAgICAgICAgICBkYXRhID0gbWlub3JfY29uc2Vuc3VzX3Bsb3RkYXRhICU+JQogICAgICAgICAgICAgICAgICAgIGZpbHRlcihyYW5rIDwgNTApLAogICAgICAgICAgICAgICAgICAgIGFlcyh4ID0gbnRwb3MsIHkgPSBuLCBsYWJlbCA9IG50cG9zLCBjb2xvciA9IGNvbnNlbnN1cywgZmlsbCA9IGNvbnNlbnN1cykpCm1pbm9yX3ByZXZhbGVuY2VfYWNyb3NzX2dlbm9tZV91bmxvZ19sYWJlbGVkCgpnZW5lcyA8LSBmcmVhZCgibnRwb3NfZ2VuZV91cGRhdGUuY3N2IiwgZGF0YS50YWJsZSA9IEYpCgpnZW5lX2xpbWl0czwtIGdlbmVzICU+JSBncm91cF9ieShnZW5lX2lkKSAlPiUgc3VtbWFyaXNlKHN0YXJ0PW1pbihudHBvcyksIGVuZD1tYXgobnRwb3MpKSAlPiUgZmlsdGVyKGdlbmVfaWQhPSIiKSAlPiUgbXV0YXRlKG1vbGVjdWxlPSIiKQoKZ2VuZV9hcnJvd3M8LWdncGxvdChnZW5lX2xpbWl0cywgYWVzKHhtaW4gPSBzdGFydCwgeG1heCA9IGVuZCwgeT1tb2xlY3VsZSwgbGFiZWwgPSBnZW5lX2lkKSkgKwogIGdlb21fZ2VuZV9hcnJvdyhhcnJvd2hlYWRfaGVpZ2h0ID0gdW5pdCgzLCAibW0iKSwgYXJyb3doZWFkX3dpZHRoID0gdW5pdCgxLCAibW0iKSkgKyBnZW9tX2dlbmVfbGFiZWwoKSArIGdlb21fc2VnbWVudChhZXMoeD0yNjYseT0xLjUseGVuZD0xMzQ2OCx5ZW5kPTEuNSksIHNpemU9MC4yKSArIHhsaW0oMCwyOTkwMykgKwogIGFubm90YXRlKCJ0ZXh0IiwgbGFiZWw9Ik9SRjFhIiwgeD01MDAwLCB5PTEuNDEsIHNpemU9MykgKyBnZW9tX3NlZ21lbnQoYWVzKHg9MTM0NjgseT0xLjQseGVuZD0yMTU1NSx5ZW5kPTEuNCksIHNpemU9MC4yKSArIGFubm90YXRlKCJ0ZXh0IiwgbGFiZWw9Ik9SRjFiIiwgeD0xODAwMCwgeT0xLjMxLCBzaXplPTMpICsKICB0aGVtZV9nZW5lcygpICsgeWxhYihOVUxMKSArIHhsYWIoTlVMTCkgCgoKKCgKICBnZW5vbWVfZmlnX3VubG9nPC1wbG90X2dyaWQoZ2VuZV9hcnJvd3MsIG1pbm9yX3ByZXZhbGVuY2VfYWNyb3NzX2dlbm9tZV91bmxvZ19sYWJlbGVkICsgdGhlbWUobGVnZW5kLnBvc2l0aW9uID0gImJvdHRvbSIpLCBucm93PTIsIHJlbF9oZWlnaHRzPWMoMC4yNSwxKSwgYXhpcz0ibHIiLCBhbGlnbj0iaHYiKQopKQoKCgpnZ3NhdmUoImdnc2F2ZS9nZW5vbWVfZmlnX3VubG9nLnBkZiIsIHBsb3QgPSBnZW5vbWVfZmlnX3VubG9nLCBoZWlnaHQgPSA1LCB3aWR0aCA9IDEyKQpgYGAKCiMjIENoYXJhY3RlcmlzdGljcyBvZiBoaWdobHkgcmVjdXJyZW50IG1pbm9yIHZhcmlhbnRzCmBgYHtyfQojIFdoYXQncyB0aGUgcmFuZ2Ugb2YgbWlub3IgYWxsZWxlIGZyZXF1ZW5jaWVzIHRoZSBoaWdobHkgcmVjdXJyZW50IG1pbm9yIHZhcmlhbnRzIGFyZSBmb3VuZCBhdD8KaGlnaGx5X3NoYXJlZF9zaXRlc190b3BfcmFua2VkID0gaGlnaGx5X3NoYXJlZF9zaXRlc19yYW5rZWQgJT4lIGZpbHRlcihyYW5rIDw9IDM1KQpoaWdobHlfc2hhcmVkX3NpdGVzID0gcGF0aWVudF92YXJfMzBfZm9yX3JhbmsgJT4lIGZpbHRlcihwYXN0ZTAoZ2VuZSwiLiIsbGFiZWwpICVpbiUKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHBhc3RlMChoaWdobHlfc2hhcmVkX3NpdGVzX3RvcF9yYW5rZWQkZ2VuZSwgIi4iLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBoaWdobHlfc2hhcmVkX3NpdGVzX3RvcF9yYW5rZWQkbGFiZWwpKSAlPiUKICAgICAgICAgIGdyb3VwX2J5KGxhYmVsLCBudHBvcykgJT4lIAogIHN1bW1hcml6ZShudHBvcywgbnRwb3NfY291bnQgPSBuKCkpICU+JSBkaXN0aW5jdCgpICU+JSAKICBhcnJhbmdlKC1udHBvc19jb3VudCkgJT4lIAogIGZpbHRlcihudHBvc19jb3VudCA+IChwYXRpZW50X3Zhcl8zMCRNQ29WTnVtYmVyICU+JSB1bmlxdWUgJT4lIGxlbmd0aCkqMC4wMSkgJT4lIHB1bGwobnRwb3MpCgoKKCgKICBoc3NfbWFmPC1wYXRpZW50X3Zhcl8zMCAlPiUgZmlsdGVyKG50cG9zICVpbiUgaGlnaGx5X3NoYXJlZF9zaXRlcykgJT4lIAogICAgZ2dwbG90KGFlcyh4ID0gYXMuZmFjdG9yKG50cG9zKSwgeSA9IG1pbm9yZnJlcSkpICsgCiAgICBnZW9tX3BvaW50KGFscGhhID0gMC4yLCBwb3NpdGlvbiA9IHBvc2l0aW9uX2ppdHRlcih3aWR0aCA9IDAuMSkpICsgdGhlbWVfYncoKSArIAogICAgZ2VvbV9ib3hwbG90KG91dGxpZXIuc2hhcGUgPSBOQSwgYWxwaGEgPTAuNSkgKyAKICAgIHRoZW1lKGF4aXMudGV4dC54ID0gZWxlbWVudF90ZXh0KGFuZ2xlPTkwKSkgKyAjZ2VvbV9ib3hwbG90KG91dGxpZXIuYWxwaGEgPSAwKSArIAogICAgeGxhYigiTnVjbGVvdGlkZSBwb3NpdGlvbiIpICsgeWxhYigiTWlub3IgYWxsZWxlIGZyZXEiKSArIAogICAgc2NhbGVfeV9jb250aW51b3VzKHRyYW5zPSJsb2cyIiwgYnJlYWtzID0gYygwLjAxKjJeKDA6NSksIDAuNSkpCiAgKSkKCmdnc2F2ZSgiZ2dzYXZlL2hzc19tYWYucGRmIiwgd2lkdGggPSA0LCBoZWlnaHQgPSAxLCBwbG90ID0gaHNzX21hZikKCigoCiAgaHNzX21hZl91bmxvZzwtcGF0aWVudF92YXJfMzAgJT4lIGZpbHRlcihudHBvcyAlaW4lIGhpZ2hseV9zaGFyZWRfc2l0ZXMpICU+JSAKICAgIGdncGxvdChhZXMoeCA9IGFzLmZhY3RvcihudHBvcyksIHkgPSBtaW5vcmZyZXEpKSArIAogICAgZ2VvbV9wb2ludChhbHBoYSA9IDAuMiwgcG9zaXRpb24gPSBwb3NpdGlvbl9qaXR0ZXIod2lkdGggPSAwLjEpKSArIHRoZW1lX2J3KCkgKyAKICAgIGdlb21fYm94cGxvdChvdXRsaWVyLnNoYXBlID0gTkEsIGFscGhhID0gMC41KSArIAogICAgdGhlbWUoYXhpcy50ZXh0LnggPSBlbGVtZW50X3RleHQoYW5nbGU9OTApKSArICNnZW9tX2JveHBsb3Qob3V0bGllci5hbHBoYSA9IDApICsgCiAgICB4bGFiKCJOdWNsZW90aWRlIHBvc2l0aW9uIikgKyB5bGFiKCJNaW5vciBhbGxlbGUgZnJlcSIpICMrIAogICAgI3NjYWxlX3lfY29udGludW91cyh0cmFucz0ibG9nMiIsIGJyZWFrcyA9IGMoMC4wMSoyXigwOjUpLCAwLjUpKQogICkpCmdnc2F2ZSgiZ2dzYXZlL2hzc19tYWZfdW5sb2cucGRmIiwgd2lkdGggPSA0LCBoZWlnaHQgPSAyLCBwbG90ID0gaHNzX21hZl91bmxvZykKCmBgYAoKCmBgYHtyLCBmaWcuaGVpZ2h0ID0gMTB9CiNIb3cgbWFueSBkaWZmZXJlbnQgY2hhbmdlcyBkbyB5b3UgZmluZCBhdCBlYWNoIHJlY3VycmVudGx5LW11dGF0ZWQgcG9zaXRpb24/IEhvdyBtYW55IHN1Y2ggbXV0YXRpb25zIGFyZSBhIHJldmVyc2lvbiB0byB0aGUgcmVmZXJlbmNlPwpoc3NfaW5mbyA8LSBmcmVhZCgnaHNzX2RhdGEyLmNzdicsIGRhdGEudGFibGUgPSBGKQoKKCgKICBoc3NfcGxvdCA9IHBhdGllbnRfdmFyXzMwX2Zvcl9yYW5rICU+JSBtdXRhdGUobGFiZWxfZ2VuZSA9IHBhc3RlMChnZW5lLCAiOiAiLCBsYWJlbCkpICU+JQogICAgZmlsdGVyKG50cG9zICVpbiUgaGlnaGx5X3NoYXJlZF9zaXRlcykgJT4lIAogICAgZ3JvdXBfYnkobnRwb3MsIG1ham9yLCBtaW5vcikgJT4lIG11dGF0ZShuPW4oKSwgbWVkaWFuX2ZyZXF1ZW5jeSA9IG1lZGlhbihtaW5vcmZyZXEpKSAlPiUgICAgIG11dGF0ZShjaGFuZ2U9cGFzdGUwKG1ham9yLCI+IixtaW5vcikpICU+JSAKICAgIG11dGF0ZShyZWZfcmV2ZXJzaW9uPWlmX2Vsc2UobWlub3I9PXJlZm50LCJ5ZXMiLCJubyIpKSAlPiUgCiAgICBtdXRhdGUobWVkaWFuX01BRj1pZl9lbHNlKG1lZGlhbl9mcmVxdWVuY3k8MC4wMiwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJsb3cgKG1lZGlhbiA8MiUgTUFGKSIsImhpZ2ggKG1lZGlhbiA+PTIlIE1BRikiKSkgJT4lCiAgICBzZWxlY3QoY2hhbmdlLCBuLCByZWZfcmV2ZXJzaW9uLCBudHBvcywgbGFiZWxfZ2VuZSwgbWVkaWFuX01BRikgJT4lIGRpc3RpbmN0ICU+JQogICAgZ2dwbG90KGFlcyh4PWNoYW5nZSwgeT1uLCBjb2xvcj1yZWZfcmV2ZXJzaW9uKSkgKyAKICAgIGdlb21fYmFyKHN0YXQ9ImlkZW50aXR5IiwgYWVzKGZpbGw9bWVkaWFuX01BRikpICsgCiAgICBzY2FsZV9jb2xvcl9tYW51YWwodmFsdWVzPWMoIndoaXRlIiwicmVkIikpICsgCiAgICBzY2FsZV9maWxsX21hbnVhbCh2YWx1ZXM9YygiZGFya21hZ2VudGEiLCJzdGVlbGJsdWUiKSkgKyAKICAgIGZhY2V0X3dyYXAobnRwb3N+bGFiZWxfZ2VuZSwgc2NhbGVzPSJmcmVlIikgKyAKICAgIHRoZW1lX3B1YnIoKSArIHRoZW1lKGF4aXMudGV4dC54PWVsZW1lbnRfdGV4dChhbmdsZT05MCkpCikpCgpnZ3NhdmUoJ2dnc2F2ZS9oc3NfcGxvdC5wZGYnLCBwbG90ID0gaHNzX3Bsb3QsIHdpZHRoID0gMTEsIGhlaWdodCA9IDEzKQpgYGAKCgpgYGB7cn0KbGRtX3ZlY3RvciA9IGxpbmVhZ2VfZGVmaW5pbmdfbXV0YXRpb25zJG50X3BvcwpoZWF0bWFwX3NwZWN0cmFfdG1wID0gcGF0aWVudF92YXJfMzBfZm9yX3JhbmsgJT4lIAogIG11dGF0ZShsYWJlbF9nZW5lID0gcGFzdGUwKGdlbmUsICI6ICIsIGxhYmVsKSkgJT4lCiAgICBmaWx0ZXIobnRwb3MgJWluJSBoaWdobHlfc2hhcmVkX3NpdGVzKSAlPiUgCiAgICBncm91cF9ieShudHBvcywgbWFqb3IsIG1pbm9yKSAlPiUgbXV0YXRlKG49bigpLCBtZWRpYW5fZnJlcXVlbmN5ID0gbWVkaWFuKG1pbm9yZnJlcSkpICU+JQogIG11dGF0ZShjaGFuZ2U9cGFzdGUwKG1ham9yLCI+IixtaW5vciksIAogICAgICAgICB0cmFuc2l0aW9uID0gaWZlbHNlKGNoYW5nZSAlaW4lIGMoIkM+VCIsIlQ+QyIsIkE+RyIsIkc+QSIpLCAxLCAwKSkgJT4lCiAgICAgbXV0YXRlKHJlZl9yZXZlcnNpb249aWZfZWxzZShtaW5vcj09cmVmbnQsMSwwKSkgJT4lIHVuZ3JvdXAoKSAlPiUKICBzZWxlY3QoY2hhbmdlLCBuLCBudHBvcywgbGFiZWxfZ2VuZSkgJT4lIGRpc3RpbmN0ICU+JSAKICBncm91cF9ieShudHBvcykgJT4lIG11dGF0ZShudHBvc19uID0gc3VtKG4pKSAlPiUgdW5ncm91cCgpICU+JQogIG11dGF0ZShuX3Byb3AgPSBuL250cG9zX24pICU+JSBzZWxlY3QoLW4pICU+JSAKICBtdXRhdGUobGRtID0gYXMuZmFjdG9yKGlmZWxzZShudHBvcyAlaW4lIGxkbV92ZWN0b3IsIDEsIDApKSkgJT4lCiAgbXV0YXRlKGxhYmVsID0gcGFzdGUwKGxhYmVsX2dlbmUsICIgLSAiLCBudHBvcywgIiAoIiwgbnRwb3NfbiwgIikiKSkKCgphbm5vdGF0aW9uX3Jvd19kZiA9IGhlYXRtYXBfc3BlY3RyYV90bXAgJT4lIHNlbGVjdChsYWJlbCwgbGRtKSAlPiUgCiAgZGlzdGluY3QgJT4lIGFzLmRhdGEuZnJhbWUoKSAlPiUKICBjb2x1bW5fdG9fcm93bmFtZXMoImxhYmVsIikKYW5ub3RhdGlvbl9yb3dfZGYKIyU+JQpoZWF0bWFwX3NwZWN0cmEgPSBoZWF0bWFwX3NwZWN0cmFfdG1wICU+JSBzZWxlY3QoLWxkbSkgJT4lIHNwcmVhZChjaGFuZ2UsIG5fcHJvcCkgJT4lIAogIGFycmFuZ2UoLW50cG9zX24pICU+JSBkaXN0aW5jdCgpICU+JSAgCiAgc2VsZWN0KC1jKG50cG9zLCBsYWJlbF9nZW5lLCBudHBvc19uKSkgJT4lIHJlcGxhY2UoLixpcy5uYSguKSwwKSAlPiUKICBjb2x1bW5fdG9fcm93bmFtZXMoImxhYmVsIikKCmFubm90YXRpb25fY29sX2RmID0gaGVhdG1hcF9zcGVjdHJhX3RtcCAlPiUgc2VsZWN0KGNoYW5nZSkgJT4lIGRpc3RpbmN0ICU+JSAKICBtdXRhdGUodHJhbnN2ZXJzaW9uID0gCiAgICAgICAgICAgYXMuZmFjdG9yKGlmZWxzZSghKGNoYW5nZSAlaW4lIGMoIkM+VCIsIlQ+QyIsIkE+RyIsIkc+QSIpKSwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAxLCAwKSkpICU+JSAKICBjb2x1bW5fdG9fcm93bmFtZXMoImNoYW5nZSIpCgptYWYgPSBoZWF0bWFwX3NwZWN0cmFfdG1wICU+JSBzZWxlY3QobnRwb3MsIGxhYmVsKSAlPiUgZGlzdGluY3QgJT4lCiAgbGVmdF9qb2luKHBhdGllbnRfdmFyXzMwICU+JSBzZWxlY3QobnRwb3MsIG1pbm9yZnJlcSkpICU+JSAKICBzZWxlY3QobGFiZWwsIG1pbm9yZnJlcSkKbWFmX2xpc3QgPSBzcGxpdChtYWYkbWlub3JmcmVxLG1hZiRsYWJlbCkKCnJvd19oYSA9IHJvd0Fubm90YXRpb24oZGYgPSBkYXRhLmZyYW1lKAogIGxkbSA9IGFubm90YXRpb25fcm93X2RmW3Jvd25hbWVzKGhlYXRtYXBfc3BlY3RyYSksXSksIAogIGNvbCA9IGxpc3QobGRtID0gYyhgMWA9ImdyZXkiLCBgMGA9IndoaXRlIikpLAogIE1BRiA9IGFubm9fYm94cGxvdChtYWZfbGlzdCwgcGNoID0gMjAsIHNpemUgPSB1bml0KDAuNSwgIm1tIikpKQoKCmhlYXRtYXBfc3BlY3RyYV9yZW9yZGVyID0gaGVhdG1hcF9zcGVjdHJhICU+JSBzZWxlY3QoYygiQT5HIiwiRz5BIiwiQz5UIiwiVD5DIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiQT5DIiwgIkM+QSIsICJBPlQiLCAiVD5BIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiQz5HIiwgIkc+QyIsICJHPlQiLCAiVD5HIikpCmNvbF9oYSA9IGNvbHVtbkFubm90YXRpb24oZGYgPSBkYXRhLmZyYW1lKAogIHRyYW5zdmVyc2lvbiA9IGFubm90YXRpb25fY29sX2RmW2NvbG5hbWVzKGhlYXRtYXBfc3BlY3RyYV9yZW9yZGVyKSxdKSwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgY29sID0gbGlzdCh0cmFuc3ZlcnNpb24gPSBjKGAxYD0iZ3JleSIsIGAwYD0id2hpdGUiKSkpCgpoZWF0bWFwX3NwZWN0cmFfaHNzID0gSGVhdG1hcChoZWF0bWFwX3NwZWN0cmFfcmVvcmRlciwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbmFtZSA9ICJwcm9wL3NpdGUiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICBjb2wgPSBjb2xvclJhbXBQYWxldHRlKAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGMoIndoaXRlIiwgImJyb3duNCIpKSgxMDApLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICBzaG93X3Jvd19kZW5kID0gRiwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGNsdXN0ZXJfY29sdW1ucyA9IEYsIGxlZnRfYW5ub3RhdGlvbiA9IHJvd19oYSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcmVjdF9ncCA9IGdwYXIoY29sID0gImdyZXk5MCIsIGx3ZCA9IDEpLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICB0b3BfYW5ub3RhdGlvbiA9IGNvbF9oYSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgaGVhdG1hcF9sZWdlbmRfcGFyYW0gPSAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBsaXN0KGRpcmVjdGlvbiA9ICJ2ZXJ0aWNhbCIpKSAKCnBkZihxcSgiZ2dzYXZlL2hlYXRtYXBfc3BlY3RyYV9oc3MucGRmIiksIHdpZHRoID0gNi41LCBoZWlnaHQgPSA3KQpkcmF3KGhlYXRtYXBfc3BlY3RyYV9oc3MsIG1lcmdlX2xlZ2VuZCA9IFRSVUUsIAogICAgIGhlYXRtYXBfbGVnZW5kX3NpZGUgPSAicmlnaHQiLCAKICAgIGFubm90YXRpb25fbGVnZW5kX3NpZGUgPSAicmlnaHQiKQpkZXYub2ZmKCkKCmhlYXRtYXBfc3BlY3RyYV9oc3MKIyAKIyAgICAgICAgICAgYm9yZGVyX2NvbG9yID0gImdyZXk5MCIsIGNvbG9yUmFtcFBhbGV0dGUoYygid2hpdGUiLCAiYnJvd240IikpKDEwMCksCiMgICAgICAgICAgdHJlZWhlaWdodF9yb3cgPSAwLCB0cmVlaGVpZ2h0X2NvbCA9IDEwLCBhbm5vdGF0aW9uX2NvbCA9IGFubm90YXRpb25fY29sX2RmLAojICAgICAgICAgIGFubm90YXRpb25fcm93ID0gYW5ub3RhdGlvbl9yb3dfZGYsIGFubm90YXRpb25fY29sb3JzID0gYW5ub3RhdGlvbl9jb2xvcnMpCiMgcGFjbWFuOjpwX2xvYWQoQ29tcGxleEhlYXRtYXApCiAgICAgICAgIApgYGAKYGBgIHtyfQojIHNhbXBsZXMgb2YgbWlub3IgdmFyaWFudCAvIHNhbXBsZXMgY29uc2Vuc3VzIHZhcmlhbnQgcGVyIHNlcXVlbmNpbmcgcnVuCiMgY29uc2Vuc3VzIDwtZnJlYWQoImNvbnNlbnN1c19taW5vcl9jaGFuZ2VzXzIwMjIwNzEzLmNzdiIsIGRhdGEudGFibGUgPSBGKSAlPiUgCiMgICBmaWx0ZXIoIW50cG9zICVpbiUgcHJvYmxlbV9zaXRlcykgJT4lIAojICAgZmlsdGVyKCFudHBvcyAlaW4lIGMoMToyNjUpKSAlPiUgCiMgICBmaWx0ZXIoIW50cG9zPjI5Njc0KQojIAojIGNvbnNlbnN1c19jb3VudCA9IGNvbnNlbnN1cyAlPiUKIyAgIG11dGF0ZShNQ29WTnVtYmVyID0gbWNvdl9yZWZvcm1hdChuYW1lKSkgJT4lCiMgICBzZWxlY3QoTUNvVk51bWJlciwgbWFqb3IsIG50cG9zLCByZWZudCkgJT4lCiMgICBmaWx0ZXIobWFqb3IgIT0gcmVmbnQpICU+JQojICAgdW5pcXVlKCkgJT4lCiMgICBncm91cF9ieShudHBvcykgJT4lCiMgICBzdW1tYXJpemUoTUNvVk51bWJlciA9IHVuaXF1ZShNQ29WTnVtYmVyKSkKIyAKIyBydW5zID0gZnJlYWQoInNhbXBsZV9kYXRlX2FuZF9ydW4uY3N2IiwgZGF0YS50YWJsZSA9IEYpICU+JQojICAgICBtdXRhdGUoTUNvVk51bWJlciA9IG1jb3ZfcmVmb3JtYXQobWNvdl9pZCkpCiMgCiMgY29uc2Vuc3VzX3J1bnMgPSBjb25zZW5zdXNfY291bnQgJT4lIGxlZnRfam9pbihydW5zKSAlPiUgZHJvcF9uYSgpICU+JQojICAgc2VsZWN0KG50cG9zLCBNQ29WTnVtYmVyX3Bvc3NpYmxlX2NvbnRhbWluYW50ID0gTUNvVk51bWJlciwgcnVuX2NvbnNlbnN1cyA9IHJ1bl9ncm91cCkgI2hhcyBlYWNoIG9mIHRoZSBjb25zZW5zdXMgbXV0YXRpb25zIHdpdGggdGhlIE1DT1YKIyB3cml0ZV9mZWF0aGVyKGNvbnNlbnN1c19ydW5zLCAicHJvY2Vzc2luZy9jb25zZW5zdXNfcnVucy5hcnJvdyIpCmNvbnNlbnN1c19ydW5zID0gcmVhZF9mZWF0aGVyKCJwcm9jZXNzaW5nL2NvbnNlbnN1c19ydW5zLmFycm93IikKCgptYWpvcl9taW5vcl90YWJsZSA9IGZ1bmN0aW9uKGNvbnNlbnN1c19ydW5zID0gY29uc2Vuc3VzX3J1bnMsIGFsbCA9IEYsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgIG91dGZpbGUgPSAiZ2dzYXZlL2hlYXRtYXBfcnVuX211dGF0aW9uLnBkZiIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgdGhyZXNob2xkX3NpdGVzID0gTlVMTCkgewogIHJ1bl9udHBvc19tYWpvcl9jb3VudCA9IGNvbnNlbnN1c19ydW5zICU+JSAKICAgIGdyb3VwX2J5KHJ1bj1ydW5fY29uc2Vuc3VzLCBudHBvcykgJT4lIAogIHN1bW1hcml6ZShtYWpvcl9jb3VudCA9IG4oKSkKIyBub3cgYnVpbGQgIyBtaW5vciB2YXJpYW50IHBlciBwb3NpdGlvbiBwZXIgcnVuCiAgcnVuX250cG9zX21pbm9yX2NvdW50ID0gcGF0aWVudF92YXJfMzAgJT4lIHNlbGVjdChNQ29WTnVtYmVyLCBydW4sIG50cG9zKSAlPiUgCiAgICBncm91cF9ieShydW4sIG50cG9zKSAlPiUgc3VtbWFyaXplKG1pbm9yX2NvdW50ID0gbigpKQogIGlmIChhbGwgPT0gRikgewogICAgcnVuX250cG9zX21pbm9yX2NvdW50X2ZpbHRlcmVkID0gcnVuX250cG9zX21pbm9yX2NvdW50ICU+JSAKICAgICAgZmlsdGVyKG50cG9zICVpbiUgaGlnaGx5X3NoYXJlZF9zaXRlcykKICB9IGVsc2UgewogICAgcnVuX250cG9zX21pbm9yX2NvdW50X2ZpbHRlcmVkID0gcnVuX250cG9zX21pbm9yX2NvdW50ICU+JSAKICAgICAgZmlsdGVyKG50cG9zICVpbiUgdGhyZXNob2xkX3NpdGVzKQogIH0KICAgIGNvbWJpbmVkX21pbm9yX21ham9yX3RhYmxlID0gIHJ1bl9udHBvc19taW5vcl9jb3VudF9maWx0ZXJlZCAlPiUgCiAgICBsZWZ0X2pvaW4ocnVuX250cG9zX21ham9yX2NvdW50KSAlPiUgcmVwbGFjZSguLGlzLm5hKC4pLDApICU+JQogICAgbXV0YXRlKHJ1biA9IGFzLm51bWVyaWMocGFyc2VfbnVtYmVyKHJ1bikpKQogIAogIG1pbm9yX3J1biA9IGNvbWJpbmVkX21pbm9yX21ham9yX3RhYmxlICU+JSBzZWxlY3QoLW1ham9yX2NvdW50KSAlPiUgCiAgICBwaXZvdF93aWRlcihuYW1lc19mcm9tID0gbnRwb3MsIHZhbHVlc19mcm9tID0gbWlub3JfY291bnQpICU+JSAKICAgIHJlcGxhY2UoLixpcy5uYSguKSwwKSAlPiUgY29sdW1uX3RvX3Jvd25hbWVzKCJydW4iKQogIAogIG1ham9yX3J1biA9IGNvbWJpbmVkX21pbm9yX21ham9yX3RhYmxlICU+JSBzZWxlY3QoLW1pbm9yX2NvdW50KSAlPiUgCiAgICBwaXZvdF93aWRlcihuYW1lc19mcm9tID0gbnRwb3MsIHZhbHVlc19mcm9tID0gbWFqb3JfY291bnQpICU+JSAKICAgIHJlcGxhY2UoLixpcy5uYSguKSwwKSAlPiUgY29sdW1uX3RvX3Jvd25hbWVzKCJydW4iKQogIAogIG1ham9yX3J1bl9ub3JtID0gYXBwbHkobWFqb3JfcnVuLCAyLCBub3JtYWxpemUpICU+JSBhcy5kYXRhLmZyYW1lKCkgJT4lIAogICAgcmVwbGFjZSguLGlzLm5hKC4pLDApIAogIG1pbm9yX3J1bl9ub3JtID0gYXBwbHkobWlub3JfcnVuLCAyLCBub3JtYWxpemUpICU+JSBhcy5kYXRhLmZyYW1lKCkgJT4lIAogICAgcmVwbGFjZSguLGlzLm5hKC4pLDApIAogIAogIAogIG1ham9yX2hlYXRtYXAgPSBIZWF0bWFwKHQobWFqb3JfcnVuX25vcm0pLAogICAgICAgICAgICAgICAgICAgICAgICAgIGNvbCA9IG1ha28oMTAwKSwgY2x1c3Rlcl9jb2x1bW5zID0gRiwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgY2x1c3Rlcl9yb3dzID0gRiwKICAgICAgICAgIGNvbHVtbl9uYW1lc19ncCA9IGdwYXIoZm9udHNpemUgPSA0KSwKICAgICAgICAgIGJvcmRlcl9ncCA9IGdwYXIoY29sID0gTkEpLCBjb2x1bW5fdGl0bGUgPSAibWFqb3IiKQogIG1pbm9yX2hlYXRtYXAgPSBIZWF0bWFwKHQobWlub3JfcnVuX25vcm0pLCBjb2wgPSBtYWtvKDEwMCksIAogICAgICAgICAgICAgICAgICAgICAgICAgIGNsdXN0ZXJfY29sdW1ucyA9IEYsIGNsdXN0ZXJfcm93cyA9IFQsIAogICAgICAgICAgICAgICAgICAgICAgICAgIGNvbHVtbl9uYW1lc19ncCA9IGdwYXIoZm9udHNpemUgPSA0KSwKICAgICAgICAgICAgICAgICAgICAgICAgICBib3JkZXJfZ3AgPSBncGFyKGNvbCA9IE5BKSwgY29sdW1uX3RpdGxlID0gIm1pbm9yIiwpCiAgCiAgIyBjb250cmFzdCBoZWF0bWFwIGlzIGluIGxvZzJGQyBvZiBjb3VudHMKICBjb2xfZnVuID0gY29sb3JSYW1wMihjKC0xLCAwLCAxKSwgYygic3RlZWxibHVlIiwgIndoaXRlIiwgInJlZCIpKQogIGNvbnRyYXN0X2hlYXRtYXAgPSBIZWF0bWFwKCh0KGxvZzIobWlub3JfcnVuX25vcm0rMSkpLQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHQobG9nMihtYWpvcl9ydW5fbm9ybSsxKSkpLCBjb2wgPSBjb2xfZnVuLCAKICAgICAgICAgICAgICAgICAgICAgICAgICBjbHVzdGVyX2NvbHVtbnMgPSBGLCBjbHVzdGVyX3Jvd3MgPSBULCAKICAgICAgICAgICAgICAgICAgICAgICAgICBjb2x1bW5fbmFtZXNfZ3AgPSBncGFyKGZvbnRzaXplID0gNCksCiAgICAgICAgICAgICAgICAgICAgICAgICAgYm9yZGVyX2dwID0gZ3Bhcihjb2wgPSBOQSksIGNvbHVtbl90aXRsZSA9ICJsb2cyKChtaW5vcisxKS8obWFqb3IrMSkpIiwgbmFtZSA9ICJsb2cyRkMiKQogIHBkZihxcShvdXRmaWxlKSwgd2lkdGggPSA2LjUsIGhlaWdodCA9IDcpCiAgZHJhdyhjb250cmFzdF9oZWF0bWFwICsgbWlub3JfaGVhdG1hcCArIG1ham9yX2hlYXRtYXAsCiAgICAgbWVyZ2VfbGVnZW5kID0gVFJVRSwgCiAgICAgaGVhdG1hcF9sZWdlbmRfc2lkZSA9ICJyaWdodCIsIAogICAgIGFubm90YXRpb25fbGVnZW5kX3NpZGUgPSAicmlnaHQiKQogIGRldi5vZmYoKQp9Cm1ham9yX21pbm9yX3RhYmxlKGNvbnNlbnN1c19ydW5zKQptYWpvcl9taW5vcl90YWJsZShjb25zZW5zdXNfcnVucywgYWxsID0gVCwgCiAgICAgICAgICAgICAgICAgIG91dGZpbGUgPSAiZ2dzYXZlL2hlYXRtYXBfcnVuX211dGF0aW9uX2FsbC5wZGYiLAogICAgICAgICAgICAgICAgICB0aHJlc2hvbGRfc2l0ZXMgPSBtaW5vcl9jb25zZW5zdXNfcGxvdGRhdGEkbnRwb3NbMToxMDAwXSAlPiUgdW5pcXVlKQoKYGBgCgoKYGBge3J9CiNhbGwgbWlub3IgdmFyaWFudHMgdGhhdCBhcmUgZm91bmQgaW4gYXQgbGVhc3QgMiUgb2YgaGlnaC1jb3ZlcmFnZSBzYW1wbGVzIGluIEx5dGhnb2UgZXQgYWwgaHR0cHM6Ly93d3cuc2NpZW5jZS5vcmcvZG9pL3N1cHBsLzEwLjExMjYvc2NpZW5jZS5hYmcwODIxL3N1cHBsX2ZpbGUvYWJnMDgyMS1seXRoZ29lLXNtLnBkZgpseXRoZ29lX2hzczwtYygyOTMyMCwgMjU2MjgsIDI1ODA3LCAyMDM2NCwgMzU3LCAyNTYyNywgMjU1MzIsIDExMDgzLCAyMzksIDIzOCwgMzU2LCAxNjc0MCwgMjA5ODksIDE5MzkzLCAxNTAwOSwgMjE4MjYsIDE5OTM3LCAyNjI4OSwyODI1MywyNTUwNywyOTg2MiwxMTA1MiwyOTg2NCwyNTUyOSwzNjksMjI0NTMsMTM1NzEsMjk1MzgsMjE1NzUsNzUsMjA5OTMsMTk0NzMsMTU0NzQsNjM1LDEyMjYsMjk3NDcsMjQ5MzMsMTkyMTAsMTMzMDMsMjg5MzYsMjYzMzQsMTY4ODcpCgp0b25raW5faHNzPC1jKDExMDc1TCwgMTEwODNMLCAxMTA3NEwsIDUyMkwsIDI2NzgwTCwgMTU0N0wsIDE0NDA4TCwgMjgyNTNMLCAxMzkxNEwsIDI2MTM3TCwgNjM1TCwgMjQxTCwgMjY3ODVMLCA2ODNMLCAyMzQwM0wsIDI4ODgxTCwgMTM3NzhMLCAyNTUyMUwsIDE0ODA1TCwgOTQ5MUwsIDExMDcxTCwgMTM3ODBMLCAyMTU3NUwsIDI5MjQyTCwgOTQzMEwsIDIwM0wsIDMwMzdMLCA2ODZMLCAzMDk2TCwgMTYzNzVMLCAxNjQ2NkwsIDE3MTY3TCwgMjM1NTlMLCA5NDM4TCwgMjExMzdMLCAyOTA1MUwsIDIzNTU1TCwgMjYzMzNMLCA5NDc0TCwgMTM1NzFMLCAxNjg4N0wsIDI2Nzg3TCwgMjg2MDNMLCAyNDIxM0wsIDExNjUxTCwgMjc5MjVMLCA1MTRMLCAyNjc4MUwsIDU1OEwsIDE5MTJMLCA5NDc5TCwgMTEwNzNMLCAxMjU3OEwsIDI2MTQ0TCwgMjY2ODFMLCAyOTI0MUwpCmludGVyc2VjdChseXRoZ29lX2hzcywgaGlnaGx5X3NoYXJlZF9zaXRlcykKaW50ZXJzZWN0KHRvbmtpbl9oc3MsIGhpZ2hseV9zaGFyZWRfc2l0ZXMpCmBgYAoKYGBge3J9CmhvbW9wbGFzaWNfc2l0ZV9saXN0PC1jKDE4N0wsIDEwNTlMLCAyMDk0TCwgMzAzN0wsIDMxMzBMLCA2OTkwTCwgODAyMkwsIDEwMzIzTCwgMTA3NDFMLCAxMTA3NEwsIDExMDgzTCwgMTM0MDhMLCAxNDc4NkwsIDE1MzI0TCwgMTk2ODRMLCAyMDE0OEwsIDIxMTM3TCwgMjE1NzVMLCAyNDAzNEwsIDI0Mzc4TCwgMjU1NjNMLCAyNjE0NEwsIDI2NDYxTCwgMjY2ODFMLCAyODA3N0wsIDI4ODI2TCwgMjg4NTRMLCAyOTcwMEwpCmludGVyc2VjdChob21vcGxhc2ljX3NpdGVfbGlzdCwgaGlnaGx5X3NoYXJlZF9zaXRlcykKYGBgCgpgYGB7cn0KdGFsbHlfaW5fbWlub3JzPC1wYXRpZW50X3Zhcl8zMCAlPiUgZmlsdGVyKG50cG9zICVpbiUgaGlnaGx5X3NoYXJlZF9zaXRlcykgJT4lIGdyb3VwX2J5KG50cG9zKSAlPiUgc3VtbWFyaXNlKG5fbWlub3JfdmFyaWFudHNfaG91c3Rvbj1uKCkpICU+JSBtdXRhdGUoZnJlcV9taW5vcl92YXJpYW50c19ob3VzdG9uPW5fbWlub3JfdmFyaWFudHNfaG91c3Rvbi9ucm93KHBhdGllbnRfY291bnRzXzMwKSkKCnRhbGx5X2luX2dpc2FpZDwtZnJlYWQoJ2hzc19naXNhaWRfdGFsbGllcy5jc3YnLCBkYXRhLnRhYmxlID0gRikgJT4lIHNlbGVjdChudHBvcywgbl9jb25zZW5zdXNfdmFyaWFudHNfZ2lzYWlkPW4pICU+JSBtdXRhdGUoZnJlcV9jb25zZW5zdXNfdmFyaWFudHNfZ2lzYWlkPW5fY29uc2Vuc3VzX3ZhcmlhbnRzX2dpc2FpZC8zMTA5NDIxKSAjVVNBIGdpc2FpZCBzZXF1ZW5jZXMgYXMgb2YgNi8xMy8yMDIyCiNTVVBQIEZJRyAxMAoKdGFsbHlfaW5fbWlub3JzX2dpc2FpZCA9IGZyZWFkKCJwcm9jZXNzaW5nL3RhbGx5X2luX21pbm9ycy50eHQiLCBkYXRhLnRhYmxlID0gRikgJT4lIAogIGxlZnRfam9pbihtaW5vcl9jb25zZW5zdXNfcGxvdGRhdGEpICU+JSBtdXRhdGUobGRtID0gYXMuZmFjdG9yKGNvbnNlbnN1cykpCgp0YWxseV9pbl9taW5vcnNfZ2lzYWlkCigoCiAgZ2lzYWlkX3ZzX2htaF9wbG90ID0gI3RhbGx5X2luX21pbm9ycyAlPiUgbGVmdF9qb2luKCB0YWxseV9pbl9naXNhaWQpICU+JSAKICAgIAogICAgdGFsbHlfaW5fbWlub3JzX2dpc2FpZCAlPiUKICAgIGdncGxvdChhZXMoeD1mcmVxX21pbm9yX3ZhcmlhbnRzX2hvdXN0b24sIHk9ZnJlcV9jb25zZW5zdXNfdmFyaWFudHNfZ2lzYWlkLCAKICAgICAgICAgICAgICAgY29sb3IgPSBsZG0pKSArIGdlb21fcG9pbnQoYWxwaGE9MC41KSArIAogICAgdGhlbWVfcHVicihsZWdlbmQ9ICJyaWdodCIpICsgCiAgeGxhYigiRnJhY3Rpb24gb2Ygc2FtcGxlcyB3aXRoIG1pbm9yIHZhcmlhbnQgaW4gSG91c3RvbiBkYXRhIikgKyAKICAgIHlsYWIoIkZyYWN0aW9uIG9mIHNhbXBsZXMgd2l0aCBcbiBjb25zZW5zdXMgdmFyaWFudCBpbiBHSVNBSUQgR2xvYmFsIikgKyAKICAgIGdlb21fdGV4dF9yZXBlbChhZXMobGFiZWw9bnRwb3MpLCBtYXgub3ZlcmxhcHMgPSAxMCwgbGFiZWwuc2l6ZT0wLjEpICsgCiAgICBnZW9tX2FibGluZShzbG9wZSA9IDEsIGludGVyY2VwdCA9IDAsIGxpbmV0eXBlPSJkYXNoZWQiLCBjb2xvciA9ICJncmF5IikgKwogICAgc2NhbGVfeV9jb250aW51b3VzKHRyYW5zPSJsb2cxMCIpICsgc2NhbGVfeF9jb250aW51b3VzKHRyYW5zPSJsb2cxMCIpICsgdGhlbWUobGVnZW5kLnBvc2l0aW9uID0gImJvdHRvbSIpCikpCgpnaXNhaWRfdnNfaG1oX21hcmdpbmFsID0gZ2dNYXJnaW5hbChnaXNhaWRfdnNfaG1oX3Bsb3QsCiAgICAgICAgICAgICBncm91cENvbG91ciA9IFQsCiAgZ3JvdXBGaWxsID0gVCkKCmdnc2F2ZSgiZ2dzYXZlL2dpc2FpZF92c19obWhfcGxvdF9tYXJnaW5hbC5wZGYiLCBwbG90ID0gZ2lzYWlkX3ZzX2htaF9tYXJnaW5hbCwgd2lkdGggPSA2LCBoZWlnaHQgPSA1KQpgYGAKCmBgYHtyLCBmaWcuaGVpZ2h0ID0gNiwgZmlnLndpZHRoID0gNn0KIyBNVVRBVElPTiBTUEVDVFJBIEFOQUxZU0lTCgojIHJlcHJvZHVjaWJpbGl0eSBhbmFseXNpcyBmcm9tIFJNRCAwMQpwbG90X25vbnJlcHJvZHVjaWJsZV9zcGVjdHJhX2hlYXRtYXAgPSByZWFkUkRTKGZpbGUgPSAicGxvdF9ub25yZXByb2R1Y2libGVfc3BlY3RyYV9oZWF0bWFwLnJkcyIpCnBsb3RfcmVwcm9kdWNpYmxlX3NwZWN0cmFfaGVhdG1hcCA9IHJlYWRSRFMoZmlsZSA9ICJwbG90X3JlcHJvZHVjaWJsZV9zcGVjdHJhX2hlYXRtYXAucmRzIikKCmhtYXA8LXRhYmxlKHBhdGllbnRfdmFyXzMwJG1ham9yW3BhdGllbnRfdmFyXzMwJG1ham9yIT0iIl0sIHBhdGllbnRfdmFyXzMwJG1pbm9yW3BhdGllbnRfdmFyXzMwJG1pbm9yIT0iIl0pICU+JSBkYXRhLmZyYW1lKCkgJT4lCiAgZ2dwbG90KGFlcyh4PVZhcjEsIHk9VmFyMiwgZmlsbD1GcmVxL3N1bShGcmVxKSkpICsgZ2VvbV90aWxlKGNvbG91ciA9ICJibGFjayIpICsKICBzY2FsZV9maWxsX2dyYWRpZW50KGxvdyA9ICJ3aGl0ZSIsCiAgICAgICAgICAgICAgICAgICAgICBoaWdoID0gImRhcmtibHVlIikgKwogIHRoZW1lX21pbmltYWwoKSArICAgbGFicyhmaWxsID0gIk51bWJlciIsCiAgICAgICB4ID0gIkNvbnNlbnN1cyBhbGxlbGUiLAogICAgICAgeSA9ICJNaW5vciBhbGxlbGUiLCB0aXRsZSA9ICJQb3N0LXNhbXBsZSBmaWx0ZXIgKEN0LCBuX3ZhcikiKSAjTW9zdCBmcmVxdWVudGx5IEM+VCBtdXRhdGlvbnMKCiMgTm93IGJlZWNhdXNlIHNvbWUgcGVha3MgYXJlIHJlYWxseSBwcmV2YWxlbnQgbGlrZSB0aGUgdHdpbiBwZWFrcyBhdCAyOTE4Ny84LCAKIyBpdCdzIGltcG9ydGFudCB0byBub3QgZmFjdG9yIHRoYXQgaW4gdG9vIG11Y2guIFNvIGxldCdzIGp1c3QgYXNzaWduIHRob3NlIG11dGF0aW9ucwojIHRvIGVxdWF0ZSB0byB0aGUgbWVkaWFuIG51bWJlciBhIG11dGF0aW9uIGFwcGVhcnMgd2hpY2ggaXMgMS4KCm11dGF0aW9uX3NwZWN0cmEgPSBwYXRpZW50X3Zhcl8zMCAlPiUgdW5pdGUoY29sID0gInNwZWN0cmFfbXV0YXRpb24iLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBtYWpvciwgbnRwb3MsIG1pbm9yLCByZW1vdmUgPSBGQUxTRSkKbXV0YXRpb25fc3BlY3RyYV9jb3VudHMgPSBtdXRhdGlvbl9zcGVjdHJhICU+JSBjb3VudChzcGVjdHJhX211dGF0aW9uKQoKbXV0YXRpb25fc3BlY3RyYV9jb3VudHMgJT4lIGdncGxvdChhZXMoeT1uKSkgKyBnZW9tX2JveHBsb3QoKSArIAogIHNjYWxlX3lfY29udGludW91cyh0cmFucyA9ICJsb2cxcCIpCgptdXRhdGlvbl9zcGVjdHJhX2NvdW50cyRuICU+JSBxdWFudGlsZSgpICMgbWVkaWFuIGlzIDEKCm11dGF0aW9uX3NwZWN0cmFfdW5pcXVlID0gbXV0YXRpb25fc3BlY3RyYSAlPiUgCiAgc2VsZWN0KG1ham9yLCBtaW5vciwgc3BlY3RyYV9tdXRhdGlvbikgJT4lIHVuaXF1ZSgpCgpobWFwX3VuaXF1ZSA8LXRhYmxlKG11dGF0aW9uX3NwZWN0cmFfdW5pcXVlJG1ham9yW211dGF0aW9uX3NwZWN0cmFfdW5pcXVlJG1ham9yIT0iIl0sIG11dGF0aW9uX3NwZWN0cmFfdW5pcXVlJG1pbm9yW211dGF0aW9uX3NwZWN0cmFfdW5pcXVlJG1pbm9yIT0iIl0pICU+JSBkYXRhLmZyYW1lKCkgJT4lCiAgZ2dwbG90KGFlcyh4PVZhcjEsIHk9VmFyMiwgZmlsbD1GcmVxL3N1bShGcmVxKSkpICsgZ2VvbV90aWxlKGNvbG91ciA9ICJibGFjayIpICsgIyBncmlkIGNvbG9yCiAgc2NhbGVfZmlsbF9ncmFkaWVudChsaW1pdHMgPSBjKDAsMC40KSwgbG93ID0gIndoaXRlIiwKICAgICAgICAgICAgICAgICAgICAgIGhpZ2ggPSAiZGFya2JsdWUiKSArCiAgdGhlbWVfbWluaW1hbCgpICsgICBsYWJzKGZpbGwgPSAiRnJhY3Rpb24iLAogICAgICAgeCA9ICJDb25zZW5zdXMgYWxsZWxlIiwKICAgICAgIHkgPSAiTWlub3IgYWxsZWxlIiwgdGl0bGU9IlVuaXF1ZSBtaW5vciB2YXJpYW50cyIpCgpyZXNjYWxlX2ZpbGwgPSBmdW5jdGlvbihobWFwX3VuaXF1ZSkgewogIGhtYXBfdW5pcXVlX3Jlc2NhbGVkID0gaG1hcF91bmlxdWUgKyAKICAgIHNjYWxlX2ZpbGxfZ3JhZGllbnQobGltaXRzID0gYygwLDAuNCksIGxvdyA9ICJ3aGl0ZSIsCiAgICAgICAgICAgICAgICAgICAgICBoaWdoID0gImRhcmtibHVlIikgKwogICAgZ2VvbV9sYWJlbChmaWxsID0gIndoaXRlIiwgYWxwaGEgPSAwLjMsIGFlcyh4ID0gVmFyMSwgeSA9IFZhcjIsIGxhYmVsID0gcm91bmQoRnJlcS9zdW0oRnJlcSksIGRpZ2l0cyA9IDIpKSkKICByZXR1cm4oaG1hcF91bmlxdWVfcmVzY2FsZWQpCn0KCigoCiAgcmVwX251Y2xlb3RpZGVzID0gZ2dhcnJhbmdlKHJlc2NhbGVfZmlsbChwbG90X25vbnJlcHJvZHVjaWJsZV9zcGVjdHJhX2hlYXRtYXApLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcmVzY2FsZV9maWxsKHBsb3RfcmVwcm9kdWNpYmxlX3NwZWN0cmFfaGVhdG1hcCksIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICByZXNjYWxlX2ZpbGwoaG1hcCksIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICByZXNjYWxlX2ZpbGwoaG1hcF91bmlxdWUpLCBjb21tb24ubGVnZW5kID0gVCkKKSkKcmVwX251Y2xlb3RpZGVzCgpnZ3NhdmUoImdnc2F2ZS9oZWF0bWFwX3NwZWN0cmFfcmVwbGljYXRlX3ZhcmlhbnRzLnBkZiIsIHJlcF9udWNsZW90aWRlcywgaGVpZ2h0ID0gNiwgd2lkdGggPSA2KQpgYGAK